diff --git a/CHANGELOG.md b/CHANGELOG.md index b611130df0..0cd40a22cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ #### New Features #### Improvements +- Replace trakt lib with PyTrakt (and switch to OAuth device authentication) ([8916](https://github.com/pymedusa/Medusa/pull/8916)) #### Fixes - Fix setting default episode status (after) when adding a new show. ([8918](https://github.com/pymedusa/Medusa/pull/8918)) diff --git a/ext/readme.md b/ext/readme.md index 5b36d73039..889307a041 100644 --- a/ext/readme.md +++ b/ext/readme.md @@ -58,6 +58,7 @@ ext | **`subliminal`** | [2.1.0](https://pypi.org/project/subliminal/2.1.0/) | * ext | **`tmdbsimple`** | [2.7.0](https://pypi.org/project/tmdbsimple/2.7.0/) | **`medusa`** | - ext | **`tornado`** | [5.1.1](https://pypi.org/project/tornado/5.1.1/) | **`medusa`**, `tornroutes` | - ext | **`tornroutes`** | [0.5.1](https://pypi.org/project/tornroutes/0.5.1/) | **`medusa`** | - +ext | **`trakt`** | [2.14.1](https://pypi.org/project/trakt/2.14.1/) | **`medusa`** | - ext | `trans` | [2.1.0](https://pypi.org/project/trans/2.1.0/) | `imdbpie` | File: `trans.py` ext | `ttl-cache` | [1.6](https://pypi.org/project/ttl-cache/1.6/) | **`medusa`** | File: `ttl_cache.py` ext | **`tvdbapiv2`** | pymedusa/[bf1272c](https://github.com/pymedusa/tvdbv2/tree/bf1272c9264c280c3048e89a1920e2bf5f386284) | **`medusa`** | - diff --git a/ext/trakt/__init__.py b/ext/trakt/__init__.py new file mode 100644 index 0000000000..8578055a63 --- /dev/null +++ b/ext/trakt/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +"""A wrapper for the Trakt.tv REST API""" +try: + from trakt.core import * # NOQA +except ImportError: + pass + +version_info = (2, 14, 1) +__author__ = 'Jon Nappi' +__version__ = '.'.join([str(i) for i in version_info]) diff --git a/ext/trakt/calendar.py b/ext/trakt/calendar.py new file mode 100644 index 0000000000..872bc0a93c --- /dev/null +++ b/ext/trakt/calendar.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +"""Interfaces to all of the Calendar objects offered by the Trakt.tv API""" +from pprint import pformat +from trakt.core import get +from trakt.movies import Movie +from trakt.tv import TVEpisode +from trakt.utils import now, airs_date + +__author__ = 'Jon Nappi' +__all__ = ['Calendar', 'PremiereCalendar', 'MyPremiereCalendar', + 'ShowCalendar', 'MyShowCalendar', 'SeasonCalendar', + 'MySeasonCalendar', 'MovieCalendar', 'MyMovieCalendar'] + + +class Calendar(object): + """Base :class:`Calendar` type serves as a foundation for other Calendar + types + """ + url = None + + def __init__(self, date=None, days=7, extended=None): + """Create a new :class:`Calendar` object + + :param date: Start date of this :class:`Calendar` in the format Ymd + (i.e. 2011-04-21). Defaults to today + :param days: Number of days for this :class:`Calendar`. Defaults to 7 + days + """ + super(Calendar, self).__init__() + self.date = date or now() + self.days = days + self._calendar = [] + self.extended = extended + self._get() + + def __getitem__(self, key): + """Pass index requests through to the internal _calendar object""" + return self._calendar.__getitem__(key) + + def __iter__(self): + """Custom iterator for iterating over the episodes in this Calendar""" + return iter(self._calendar) + + def __len__(self): + """Returns the length of the episodes list in this calendar""" + return len(self._calendar) + + def __str__(self): + """str representation of this Calendar""" + return pformat(self._calendar) + __repr__ = __str__ + + @property + def ext(self): + """construct the fully formatted url for this Calendar""" + uri = '/'.join([self.url, str(self.date), str(self.days)]) + if self.extended: + uri += '?extended={extended}'.format(extended=self.extended) + return uri + + @get + def _get(self): + data = yield self.ext + self._build(data) + + def _build(self, data): + """Build the calendar""" + self._calendar = [] + for episode in data: + show = episode.get('show', {}).get('title') + season = episode.get('episode', {}).get('season') + ep = episode.get('episode', {}).get('number') + e_data = {'airs_at': airs_date(episode.get('first_aired')), + 'ids': episode.get('episode').get('ids'), + 'title': episode.get('episode', {}).get('title')} + self._calendar.append(TVEpisode(show, season, ep, **e_data)) + self._calendar = sorted(self._calendar, key=lambda x: x.airs_at) + + +class PremiereCalendar(Calendar): + """All shows premiering during the time period specified.""" + url = 'calendars/all/shows/new' + + +class MyPremiereCalendar(Calendar): + """Personalized calendar of all shows premiering during the time period + specified. + """ + url = 'calendars/my/shows/new' + + +class ShowCalendar(Calendar): + """TraktTV ShowCalendar""" + url = 'calendars/all/shows' + + +class MyShowCalendar(Calendar): + """Personalized TraktTV ShowCalendar""" + url = 'calendars/my/shows' + + +class SeasonCalendar(Calendar): + """TraktTV TV Show Season Premiere""" + url = 'calendars/all/shows/premieres' + + +class MySeasonCalendar(Calendar): + """Personalized TraktTV TV Show Season Premiere""" + url = 'calendars/my/shows/premieres' + + +class MovieCalendar(Calendar): + """TraktTV Movie Calendar. Returns all movies with a release date during + the time period specified. + """ + url = 'calendars/all/movies' + + def _build(self, data): + """Build the calendar of Movies""" + self._calendar = [] + for movie in data: + m_data = movie.get('movie', {}) + released = movie.get('released', None) + self._calendar.append(Movie(released=released, **m_data)) + + self._calendar = sorted(self._calendar, key=lambda x: x.released) + + +class MyMovieCalendar(MovieCalendar): + """Personalized TraktTV Movie Calendar.""" + url = 'calendars/my/movies' diff --git a/ext/trakt/core.py b/ext/trakt/core.py new file mode 100644 index 0000000000..4e17a52f6c --- /dev/null +++ b/ext/trakt/core.py @@ -0,0 +1,610 @@ +# -*- coding: utf-8 -*- +"""Objects, properties, and methods to be shared across other modules in the +trakt package +""" +from __future__ import print_function +import json +import logging +import os +import requests +import six +import sys +import time +from collections import namedtuple +from functools import wraps +from requests.compat import urljoin +from requests_oauthlib import OAuth2Session +from datetime import datetime, timedelta +from trakt import errors + +__author__ = 'Jon Nappi' +__all__ = ['Airs', 'Alias', 'Comment', 'Genre', 'get', 'delete', 'post', 'put', + 'init', 'BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET', 'DEVICE_AUTH', + 'REDIRECT_URI', 'HEADERS', 'CONFIG_PATH', 'OAUTH_TOKEN', + 'OAUTH_REFRESH', 'PIN_AUTH', 'OAUTH_AUTH', 'AUTH_METHOD', + 'APPLICATION_ID', 'get_device_code', 'get_device_token'] + +#: The base url for the Trakt API. Can be modified to run against different +#: Trakt.tv environments +BASE_URL = 'https://api-v2launch.trakt.tv/' + +#: The Trakt.tv OAuth Client ID for your OAuth Application +CLIENT_ID = None + +#: The Trakt.tv OAuth Client Secret for your OAuth Application +CLIENT_SECRET = None + +#: The OAuth2 Redirect URI for your OAuth Application +REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' + +#: Default request HEADERS +HEADERS = {'Content-Type': 'application/json', 'trakt-api-version': '2'} + +#: Default path for where to store your trakt.tv API authentication information +CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.pytrakt.json') + +#: Your personal Trakt.tv OAUTH Bearer Token +OAUTH_TOKEN = api_key = None + +# OAuth token validity checked +OAUTH_TOKEN_VALID = None + +# Your OAUTH token expiration date +OAUTH_EXPIRES_AT = None + +# Your OAUTH refresh token +OAUTH_REFRESH = None + +#: Flag used to enable Trakt PIN authentication +PIN_AUTH = 'PIN' + +#: Flag used to enable Trakt OAuth authentication +OAUTH_AUTH = 'OAUTH' + +#: Flag used to enable Trakt OAuth device authentication +DEVICE_AUTH = 'DEVICE' + +#: The currently enabled authentication method. Default is ``PIN_AUTH`` +AUTH_METHOD = PIN_AUTH + +#: The ID of the application to register with, when using PIN authentication +APPLICATION_ID = None + + +def _store(**kwargs): + """Helper function used to store Trakt configurations at ``CONFIG_PATH`` + + :param kwargs: Keyword args to store at ``CONFIG_PATH`` + """ + with open(CONFIG_PATH, 'w') as config_file: + json.dump(kwargs, config_file) + + +def _get_client_info(app_id=False): + """Helper function to poll the user for Client ID and Client Secret + strings + + :return: A 2-tuple of client_id, client_secret + """ + global APPLICATION_ID + print('If you do not have a client ID and secret. Please visit the ' + 'following url to create them.') + print('http://trakt.tv/oauth/applications') + client_id = six.moves.input('Please enter your client id: ') + client_secret = six.moves.input('Please enter your client secret: ') + if app_id: + msg = 'Please enter your application ID ({default}): '.format( + default=APPLICATION_ID) + user_input = six.moves.input(msg) + if user_input: + APPLICATION_ID = user_input + return client_id, client_secret + + +def pin_auth(pin=None, client_id=None, client_secret=None, store=False): + """Generate an access_token from a Trakt API PIN code. + + :param pin: Optional Trakt API PIN code. If one is not specified, you will + be prompted to go generate one + :param store: Boolean flag used to determine if your trakt api auth data + should be stored locally on the system. Default is :const:`False` for + the security conscious + :return: Your OAuth access token + """ + global OAUTH_TOKEN, CLIENT_ID, CLIENT_SECRET + CLIENT_ID, CLIENT_SECRET = client_id, client_secret + if client_id is None and client_secret is None: + CLIENT_ID, CLIENT_SECRET = _get_client_info(app_id=True) + if pin is None and APPLICATION_ID is None: + print('You must set the APPLICATION_ID of the Trakt application you ' + 'wish to use. You can find this ID by visiting the following ' + 'URL.') + print('https://trakt.tv/oauth/applications') + sys.exit(1) + if pin is None: + print('If you do not have a Trakt.tv PIN, please visit the following ' + 'url and log in to generate one.') + pin_url = 'https://trakt.tv/pin/{id}'.format(id=APPLICATION_ID) + print(pin_url) + pin = six.moves.input('Please enter your PIN: ') + args = {'code': pin, + 'redirect_uri': REDIRECT_URI, + 'grant_type': 'authorization_code', + 'client_id': CLIENT_ID, + 'client_secret': CLIENT_SECRET} + + response = requests.post(''.join([BASE_URL, '/oauth/token']), data=args) + OAUTH_TOKEN = response.json().get('access_token', None) + + if store: + _store(CLIENT_ID=CLIENT_ID, CLIENT_SECRET=CLIENT_SECRET, + OAUTH_TOKEN=OAUTH_TOKEN, APPLICATION_ID=APPLICATION_ID) + return OAUTH_TOKEN + + +def _terminal_oauth_pin(authorization_url): + """Default OAuth callback used for terminal applications. + + :param authorization_url: Predefined url by function `oauth_auth`. URL will + be prompted to you in the terminal + :return: OAuth PIN + """ + print('Please go here and authorize,', authorization_url) + + # Get the authorization verifier code from the callback url + response = six.moves.input('Paste the Code returned here: ') + return response + + +def oauth_auth(username, client_id=None, client_secret=None, store=False, + oauth_cb=_terminal_oauth_pin): + """Generate an access_token to allow your application to authenticate via + OAuth + + :param username: Your trakt.tv username + :param client_id: Your Trakt OAuth Application's Client ID + :param client_secret: Your Trakt OAuth Application's Client Secret + :param store: Boolean flag used to determine if your trakt api auth data + should be stored locally on the system. Default is :const:`False` for + the security conscious + :param oauth_cb: Callback function to handle the retrieving of the OAuth + PIN. Default function `_terminal_oauth_pin` for terminal auth + :return: Your OAuth access token + """ + global CLIENT_ID, CLIENT_SECRET, OAUTH_TOKEN + if client_id is None and client_secret is None: + client_id, client_secret = _get_client_info() + CLIENT_ID, CLIENT_SECRET = client_id, client_secret + HEADERS['trakt-api-key'] = CLIENT_ID + + authorization_base_url = urljoin(BASE_URL, '/oauth/authorize') + token_url = urljoin(BASE_URL, '/oauth/token') + + # OAuth endpoints given in the API documentation + oauth = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI, state=None) + + # Authorization URL to redirect user to Trakt for authorization + authorization_url, _ = oauth.authorization_url(authorization_base_url, + username=username) + + # Calling callback function to get the OAuth PIN + oauth_pin = oauth_cb(authorization_url) + + # Fetch, assign, and return the access token + oauth.fetch_token(token_url, client_secret=CLIENT_SECRET, code=oauth_pin) + OAUTH_TOKEN = oauth.token['access_token'] + OAUTH_REFRESH = oauth.token['refresh_token'] + OAUTH_EXPIRES_AT = oauth.token["created_at"] + oauth.token["expires_in"] + + if store: + _store(CLIENT_ID=CLIENT_ID, CLIENT_SECRET=CLIENT_SECRET, + OAUTH_TOKEN=OAUTH_TOKEN, OAUTH_REFRESH=OAUTH_REFRESH, + OAUTH_EXPIRES_AT=OAUTH_EXPIRES_AT) + return OAUTH_TOKEN + + +def get_device_code(client_id=None, client_secret=None): + """Generate a device code, used for device oauth authentication. + + Trakt docs: https://trakt.docs.apiary.io/#reference/ + authentication-devices/device-code + :param client_id: Your Trakt OAuth Application's Client ID + :param client_secret: Your Trakt OAuth Application's Client Secret + :param store: Boolean flag used to determine if your trakt api auth data + should be stored locally on the system. Default is :const:`False` for + the security conscious + :return: Your OAuth device code. + """ + global CLIENT_ID, CLIENT_SECRET, OAUTH_TOKEN + if client_id is None and client_secret is None: + client_id, client_secret = _get_client_info() + CLIENT_ID, CLIENT_SECRET = client_id, client_secret + HEADERS['trakt-api-key'] = CLIENT_ID + + device_code_url = urljoin(BASE_URL, '/oauth/device/code') + headers = {'Content-Type': 'application/json'} + data = {"client_id": CLIENT_ID} + + device_response = requests.post(device_code_url, json=data, + headers=headers).json() + print('Your user code is: {user_code}, please navigate to ' + '{verification_url} to authenticate'.format( + user_code=device_response.get('user_code'), + verification_url=device_response.get('verification_url') + )) + + device_response['requested'] = time.time() + return device_response + + +def get_device_token(device_code, client_id=None, client_secret=None, + store=False): + """ + Trakt docs: https://trakt.docs.apiary.io/#reference/ + authentication-devices/get-token + Response: + { + "access_token": "", + "token_type": "bearer", + "expires_in": 7776000, + "refresh_token": "", + "scope": "public", + "created_at": 1519329051 + } + :return: Information regarding the authentication polling. + :return type: dict + """ + global CLIENT_ID, CLIENT_SECRET, OAUTH_TOKEN, OAUTH_REFRESH + if client_id is None and client_secret is None: + client_id, client_secret = _get_client_info() + CLIENT_ID, CLIENT_SECRET = client_id, client_secret + HEADERS['trakt-api-key'] = CLIENT_ID + + data = { + "code": device_code, + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET + } + + response = requests.post(urljoin(BASE_URL, '/oauth/device/token'), + json=data) + + # We only get json on success. + if response.status_code == 200: + data = response.json() + OAUTH_TOKEN = data.get('access_token') + OAUTH_REFRESH = data.get('refresh_token') + OAUTH_EXPIRES_AT = data.get("created_at") + data.get("expires_in") + + if store: + _store( + CLIENT_ID=CLIENT_ID, CLIENT_SECRET=CLIENT_SECRET, + OAUTH_TOKEN=OAUTH_TOKEN, OAUTH_REFRESH=OAUTH_REFRESH, + OAUTH_EXPIRES_AT=OAUTH_EXPIRES_AT + ) + + return response + + +def device_auth(client_id=None, client_secret=None, store=False): + """Process for authenticating using device authentication. + + The function will attempt getting the device_id, and provide + the user with a url and code. After getting the device + id, a timer is started to poll periodic for a successful authentication. + This is a blocking action, meaning you + will not be able to run any other code, while waiting for an access token. + + If you want more control over the authentication flow, use the functions + get_device_code and get_device_token. + Where poll_for_device_token will check if the "offline" + authentication was successful. + + :param client_id: Your Trakt OAuth Application's Client ID + :param client_secret: Your Trakt OAuth Application's Client Secret + :param store: Boolean flag used to determine if your trakt api auth data + should be stored locally on the system. Default is :const:`False` for + the security conscious + :return: A dict with the authentication result. + Or False of authentication failed. + """ + error_messages = { + 404: 'Invalid device_code', + 409: 'You already approved this code', + 410: 'The tokens have expired, restart the process', + 418: 'You explicitly denied this code', + } + + success_message = ( + "You've been successfully authenticated. " + "With access_token {access_token} and refresh_token {refresh_token}" + ) + + response = get_device_code(client_id=client_id, + client_secret=client_secret) + device_code = response['device_code'] + interval = response['interval'] + + # No need to check for expiration, the API will notify us. + while True: + response = get_device_token(device_code, client_id, client_secret, + store) + + if response.status_code == 200: + print(success_message.format_map(response.json())) + break + + elif response.status_code == 429: # slow down + interval *= 2 + + elif response.status_code != 400: # not pending + print(error_messages.get(response.status_code, response.reason)) + break + + time.sleep(interval) + + return response + + +auth_method = { + PIN_AUTH: pin_auth, OAUTH_AUTH: oauth_auth, DEVICE_AUTH: device_auth +} + + +def init(*args, **kwargs): + """Run the auth function specified by *AUTH_METHOD*""" + return auth_method.get(AUTH_METHOD, PIN_AUTH)(*args, **kwargs) + + +Airs = namedtuple('Airs', ['day', 'time', 'timezone']) +Alias = namedtuple('Alias', ['title', 'country']) +Genre = namedtuple('Genre', ['name', 'slug']) +Comment = namedtuple('Comment', ['id', 'parent_id', 'created_at', 'comment', + 'spoiler', 'review', 'replies', 'user', + 'updated_at', 'likes', 'user_rating']) + + +def _validate_token(s): + """Check if current OAuth token has not expired""" + global OAUTH_TOKEN_VALID + current = datetime.utcnow() + expires_at = datetime.utcfromtimestamp(OAUTH_EXPIRES_AT) + if expires_at - current > timedelta(days=2): + OAUTH_TOKEN_VALID = True + else: + _refresh_token(s) + + +def _refresh_token(s): + """Request Trakt API for a new valid OAuth token using refresh_token""" + global OAUTH_TOKEN, OAUTH_EXPIRES_AT, OAUTH_REFRESH, OAUTH_TOKEN_VALID + s.logger.info("OAuth token has expired, refreshing now...") + url = urljoin(BASE_URL, '/oauth/token') + data = { + 'client_id': CLIENT_ID, + 'client_secret': CLIENT_SECRET, + 'refresh_token': OAUTH_REFRESH, + 'redirect_uri': REDIRECT_URI, + 'grant_type': 'refresh_token' + } + response = requests.post(url, json=data, headers=HEADERS) + s.logger.debug('RESPONSE [post] (%s): %s', url, str(response)) + if response.status_code == 200: + data = response.json() + OAUTH_TOKEN = data.get("access_token") + OAUTH_REFRESH = data.get("refresh_token") + OAUTH_EXPIRES_AT = data.get("created_at") + data.get("expires_in") + OAUTH_TOKEN_VALID = True + s.logger.info( + "OAuth token successfully refreshed, valid until", + datetime.fromtimestamp(OAUTH_EXPIRES_AT) + ) + _store( + CLIENT_ID=CLIENT_ID, CLIENT_SECRET=CLIENT_SECRET, + OAUTH_TOKEN=OAUTH_TOKEN, OAUTH_REFRESH=OAUTH_REFRESH, + OAUTH_EXPIRES_AT=OAUTH_EXPIRES_AT + ) + elif response.status_code == 401: + s.logger.debug( + "Rejected - Unable to refresh expired OAuth token, " + "refresh_token is invalid" + ) + elif response.status_code in s.error_map: + raise s.error_map[response.status_code]() + + +def _bootstrapped(f): + """Bootstrap your authentication environment when authentication is needed + and if a file at `CONFIG_PATH` exists. The process is completed by setting + the client id header. + """ + @wraps(f) + def inner(*args, **kwargs): + global CLIENT_ID, CLIENT_SECRET, OAUTH_TOKEN, OAUTH_EXPIRES_AT + global OAUTH_REFRESH, APPLICATION_ID + if (CLIENT_ID is None or CLIENT_SECRET is None) and \ + os.path.exists(CONFIG_PATH): + # Load in trakt API auth data from CONFIG_PATH + with open(CONFIG_PATH) as config_file: + config_data = json.load(config_file) + + if CLIENT_ID is None: + CLIENT_ID = config_data.get('CLIENT_ID', None) + if CLIENT_SECRET is None: + CLIENT_SECRET = config_data.get('CLIENT_SECRET', None) + if OAUTH_TOKEN is None: + OAUTH_TOKEN = config_data.get('OAUTH_TOKEN', None) + if OAUTH_EXPIRES_AT is None: + OAUTH_EXPIRES_AT = config_data.get('OAUTH_EXPIRES_AT', None) + if OAUTH_REFRESH is None: + OAUTH_REFRESH = config_data.get('OAUTH_REFRESH', None) + if APPLICATION_ID is None: + APPLICATION_ID = config_data.get('APPLICATION_ID', None) + + # Check token validity and refresh token if needed + if (not OAUTH_TOKEN_VALID and OAUTH_EXPIRES_AT is not None and + OAUTH_REFRESH is not None): + _validate_token(args[0]) + # For backwards compatability with trakt<=2.3.0 + if api_key is not None and OAUTH_TOKEN is None: + OAUTH_TOKEN = api_key + return f(*args, **kwargs) + return inner + + +class Core(object): + """This class contains all of the functionality required for interfacing + with the Trakt.tv API + """ + + def __init__(self): + """Create a :class:`Core` instance and give it a logger attribute""" + self.logger = logging.getLogger('trakt.core') + + # Get all of our exceptions except the base exception + errs = [getattr(errors, att) for att in errors.__all__ + if att != 'TraktException'] + + # Map HTTP response codes to exception types + self.error_map = {err.http_code: err for err in errs} + + @staticmethod + def _get_first(f, *args, **kwargs): + """Extract the first value from the provided generator function *f* + + :param f: A generator function to extract data from + :param args: Non keyword args for the generator function + :param kwargs: Keyword args for the generator function + :return: The full url for the resource, a generator, and either a data + payload or `None` + """ + generator = f(*args, **kwargs) + uri = next(generator) + if not isinstance(uri, (str, tuple)): + # Allow properties to safely yield arbitrary data + return uri + if isinstance(uri, tuple): + uri, data = uri + return BASE_URL + uri, generator, data + else: + return BASE_URL + uri, generator, None + + def _handle_request(self, method, url, data=None): + """Handle actually talking out to the trakt API, logging out debug + information, raising any relevant `TraktException` Exception types, + and extracting and returning JSON data + + :param method: The HTTP method we're executing on. Will be one of + post, put, delete, get + :param url: The fully qualified url to send our request to + :param data: Optional data payload to send to the API + :return: The decoded JSON response from the Trakt API + :raises TraktException: If any non-200 return code is encountered + """ + self.logger.debug('%s: %s', method, url) + HEADERS['trakt-api-key'] = CLIENT_ID + HEADERS['Authorization'] = 'Bearer {0}'.format(OAUTH_TOKEN) + self.logger.debug('headers: %s', str(HEADERS)) + self.logger.debug('method, url :: %s, %s', method, url) + if method == 'get': # GETs need to pass data as params, not body + response = requests.request(method, url, params=data, + headers=HEADERS) + else: + response = requests.request(method, url, data=json.dumps(data), + headers=HEADERS) + self.logger.debug('RESPONSE [%s] (%s): %s', method, url, str(response)) + if response.status_code in self.error_map: + raise self.error_map[response.status_code]() + elif response.status_code == 204: # HTTP no content + return None + json_data = json.loads(response.content.decode('UTF-8', 'ignore')) + return json_data + + @_bootstrapped + def get(self, f): + """Perform a HTTP GET request using the provided uri yielded from the + *f* co-routine. The processed JSON results are then sent back to the + co-routine for post-processing, the results of which are then returned + + :param f: Generator co-routine that yields uri, args, and processed + results + :return: The results of the generator co-routine + """ + @wraps(f) + def inner(*args, **kwargs): + resp = self._get_first(f, *args, **kwargs) + if not isinstance(resp, tuple): + # Handle cached property responses + return resp + url, generator, _ = resp + json_data = self._handle_request('get', url) + try: + return generator.send(json_data) + except StopIteration: + return None + return inner + + @_bootstrapped + def delete(self, f): + """Perform an HTTP DELETE request using the provided uri + + :param f: Function that returns a uri to delete to + """ + @wraps(f) + def inner(*args, **kwargs): + generator = f(*args, **kwargs) + uri = next(generator) + url = BASE_URL + uri + self._handle_request('delete', url) + return inner + + @_bootstrapped + def post(self, f): + """Perform an HTTP POST request using the provided uri and optional + args yielded from the *f* co-routine. The processed JSON results are + then sent back to the co-routine for post-processing, the results of + which are then returned + + :param f: Generator co-routine that yields uri, args, and processed + results + :return: The results of the generator co-routine + """ + @wraps(f) + def inner(*args, **kwargs): + url, generator, args = self._get_first(f, *args, **kwargs) + json_data = self._handle_request('post', url, data=args) + try: + return generator.send(json_data) + except StopIteration: + return None + return inner + + @_bootstrapped + def put(self, f): + """Perform an HTTP PUT request using the provided uri and optional args + yielded from the *f* co-routine. The processed JSON results are then + sent back to the co-routine for post-processing, the results of which + are then returned + + :param f: Generator co-routine that yields uri, args, and processed + results + :return: The results of the generator co-routine + """ + @wraps(f) + def inner(*args, **kwargs): + url, generator, args = self._get_first(f, *args, **kwargs) + json_data = self._handle_request('put', url, data=args) + try: + return generator.send(json_data) + except StopIteration: + return None + return inner + + +# Here we can simplify the code in each module by exporting these instance +# method decorators as if they were simple functions. +CORE = Core() +get = CORE.get +post = CORE.post +delete = CORE.delete +put = CORE.put diff --git a/ext/trakt/errors.py b/ext/trakt/errors.py new file mode 100644 index 0000000000..7d69f10f89 --- /dev/null +++ b/ext/trakt/errors.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +"""All Trakt related errors that are worth processing. Note that 412 response +codes are ignored because the only requests that this library sends out are +guaranteed to have the application/json MIME type set. +""" + +__author__ = 'Jon Nappi' +__all__ = ['TraktException', 'BadRequestException', 'OAuthException', + 'ForbiddenException', 'NotFoundException', 'ConflictException', + 'ProcessException', 'RateLimitException', 'TraktInternalException', + 'TraktUnavailable'] + + +class TraktException(Exception): + """Base Exception type for trakt module""" + http_code = message = None + + def __str__(self): + return self.message + + +class BadRequestException(TraktException): + """TraktException type to be raised when a 400 return code is received""" + http_code = 400 + message = "Bad Request - request couldn't be parsed" + + +class OAuthException(TraktException): + """TraktException type to be raised when a 401 return code is received""" + http_code = 401 + message = 'Unauthorized - OAuth must be provided' + + +class ForbiddenException(TraktException): + """TraktException type to be raised when a 403 return code is received""" + http_code = 403 + message = 'Forbidden - invalid API key or unapproved app' + + +class NotFoundException(TraktException): + """TraktException type to be raised when a 404 return code is received""" + http_code = 404 + message = 'Not Found - method exists, but no record found' + + +class ConflictException(TraktException): + """TraktException type to be raised when a 409 return code is received""" + http_code = 409 + message = 'Conflict - resource already created' + + +class ProcessException(TraktException): + """TraktException type to be raised when a 422 return code is received""" + http_code = 422 + message = 'Unprocessable Entity - validation errors' + + +class RateLimitException(TraktException): + """TraktException type to be raised when a 429 return code is received""" + http_code = 429 + message = 'Rate Limit Exceeded' + + +class TraktInternalException(TraktException): + """TraktException type to be raised when a 500 error is raised""" + http_code = 500 + message = 'Internal Server Error' + + +class TraktUnavailable(TraktException): + """TraktException type to be raised when a 503 error is raised""" + http_code = 503 + message = 'Trakt Unavailable - server overloaded' diff --git a/ext/trakt/movies.py b/ext/trakt/movies.py new file mode 100644 index 0000000000..b92258a89a --- /dev/null +++ b/ext/trakt/movies.py @@ -0,0 +1,380 @@ +# -*- coding: utf-8 -*- +"""Interfaces to all of the Movie objects offered by the Trakt.tv API""" +from collections import namedtuple +from trakt.core import Alias, Comment, Genre, get, delete +from trakt.sync import (Scrobbler, comment, rate, add_to_history, + remove_from_history, add_to_watchlist, + remove_from_watchlist, add_to_collection, + remove_from_collection, search, checkin_media, + delete_checkin) +from trakt.people import Person +from trakt.utils import slugify, now, extract_ids, unicode_safe + +__author__ = 'Jon Nappi' +__all__ = ['dismiss_recommendation', 'get_recommended_movies', 'genres', + 'trending_movies', 'updated_movies', 'Release', 'Movie', + 'Translation'] + +Translation = namedtuple('Translation', ['title', 'overview', 'tagline', + 'language']) + + +@delete +def dismiss_recommendation(title): + """Dismiss the movie matching the specified criteria from showing up in + recommendations. + """ + yield 'recommendations/movies/{title}'.format(title=slugify(str(title))) + + +@get +def get_recommended_movies(): + """Get a list of :class:`Movie`'s recommended based on your watching + history and your friends. Results are returned with the top recommendation + first. + """ + data = yield 'recommendations/movies' + movies = [] + for movie in data: + extract_ids(movie) + movies.append(Movie(**movie)) + yield movies + + +@get +def genres(): + """A list of all possible :class:`Movie` Genres""" + data = yield 'genres/movies' + yield [Genre(g['name'], g['slug']) for g in data] + + +@get +def trending_movies(): + """All :class:`Movie`'s being watched right now""" + data = yield '/movies/trending' + to_ret = [] + for movie in data: + watchers = movie.pop('watchers') + to_ret.append(Movie(watchers=watchers, **movie.pop('movie'))) + yield to_ret + + +@get +def updated_movies(timestamp=None): + """Returns all movies updated since a timestamp. The server time is in PST. + To establish a baseline timestamp, you can use the server/time method. It's + recommended to store the timestamp so you can be efficient in using this + method. + """ + ts = timestamp or now() + data = yield 'movies/updates/{start_date}'.format(start_date=ts) + to_ret = [] + for movie in data: + mov = movie.pop('movie') + extract_ids(mov) + mov.update({'updated_at': movie.pop('updated_at')}) + to_ret.append(Movie(**mov)) + yield to_ret + + +Release = namedtuple('Release', ['country', 'certification', 'release_date', + 'note', 'release_type']) + + +class Movie(object): + """A Class representing a Movie object""" + def __init__(self, title, year=None, slug=None, **kwargs): + super(Movie, self).__init__() + self.media_type = 'movies' + self.title = title + self.year = int(year) if year is not None else year + if self.year is not None and slug is None: + self.slug = slugify('-'.join([self.title, str(self.year)])) + else: + self.slug = slug or slugify(self.title) + + self.released = self.tmdb_id = self.imdb_id = self.duration = None + self.trakt_id = self.tagline = self.overview = self.runtime = None + self.updated_at = self.trailer = self.homepage = self.rating = None + self.votes = self.language = self.available_translations = None + self.genres = self.certification = None + self._comments = self._images = self._aliases = self._people = None + self._ratings = self._releases = self._translations = None + + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + + @classmethod + def search(cls, title, year=None): + """Perform a search for a movie with a title matching *title* + + :param title: The title to search for + :param year: Optional year to limit results to + """ + return search(title, search_type='movie', year=year) + + @get + def _get(self): + """Handle getting this :class:`Movie`'s data from trakt and building + our attributes from the returned data + """ + data = yield self.ext_full + self._build(data) + + def _build(self, data): + """Build this :class:`Movie` object with the data in *data*""" + extract_ids(data) + for key, val in data.items(): + if hasattr(self, '_' + key): + setattr(self, '_' + key, val) + else: + setattr(self, key, val) + + @property + def ext(self): + """Base uri to retrieve basic information about this :class:`Movie`""" + return 'movies/{slug}'.format(slug=self.slug) + + @property + def ext_full(self): + """Uri to retrieve all information about this :class:`Movie`""" + return self.ext + '?extended=full' + + @property + def images_ext(self): + """Uri to retrieve additional image information""" + return self.ext + '?extended=images' + + @property + @get + def aliases(self): + """A list of :class:`Alias` objects representing all of the other + titles that this :class:`Movie` is known by, and the countries where + they go by their alternate titles + """ + if self._aliases is None: + data = yield (self.ext + '/aliases') + self._aliases = [Alias(**alias) for alias in data] + yield self._aliases + + @property + def cast(self): + """All of the cast members that worked on this :class:`Movie`""" + return [p for p in self.people if getattr(p, 'character')] + + @property + @get + def comments(self): + """All comments (shouts and reviews) for this :class:`Movie`. Most + recent comments returned first. + """ + # TODO (jnappi) Pagination + from trakt.users import User + data = yield (self.ext + '/comments') + self._comments = [] + for com in data: + user = User(**com.get('user')) + self._comments.append( + Comment(user=user, **{k: com[k] for k in com if k != 'user'}) + ) + yield self._comments + + @property + def crew(self): + """All of the crew members that worked on this :class:`Movie`""" + return [p for p in self.people if getattr(p, 'job')] + + @property + def ids(self): + """Accessor to the trakt, imdb, and tmdb ids, as well as the trakt.tv + slug + """ + return {'ids': {'trakt': self.trakt, 'slug': self.slug, + 'imdb': self.imdb, 'tmdb': self.tmdb}} + + @property + @get + def images(self): + """All of the artwork associated with this :class:`Movie`""" + if self._images is None: + data = yield self.images_ext + self._images = data.get('images', {}) + yield self._images + + @property + @get + def people(self): + """A :const:`list` of all of the :class:`People` involved in this + :class:`Movie`, including both cast and crew + """ + if self._people is None: + data = yield (self.ext + '/people') + crew = data.get('crew', {}) + cast = [] + for c in data.get('cast', []): + person = c.pop('person') + character = c.pop('character') + cast.append(Person(character=character, **person)) + + _crew = [] + for key in crew: + for department in crew.get(key): # lists + person = department.get('person') + person.update({'job': department.get('job')}) + _crew.append(Person(**person)) + self._people = cast + _crew + yield self._people + + @property + @get + def ratings(self): + """Ratings (between 0 and 10) and distribution for a movie.""" + if self._ratings is None: + self._ratings = yield (self.ext + '/ratings') + yield self._ratings + + @property + @get + def related(self): + """The top 10 :class:`Movie`'s related to this :class:`Movie`""" + data = yield (self.ext + '/related') + movies = [] + for movie in data: + movies.append(Movie(**movie)) + yield movies + + @property + @get + def watching_now(self): + """A list of all :class:`User`'s watching a movie.""" + from trakt.users import User + data = yield self.ext + '/watching' + users = [] + for user in data: + users.append(User(**user)) + yield users + + def add_to_library(self): + """Add this :class:`Movie` to your library.""" + add_to_collection(self) + add_to_collection = add_to_library + + def add_to_watchlist(self): + """Add this :class:`Movie` to your watchlist""" + add_to_watchlist(self) + + def comment(self, comment_body, spoiler=False, review=False): + """Add a comment (shout or review) to this :class:`Move` on trakt.""" + comment(self, comment_body, spoiler, review) + + def dismiss(self): + """Dismiss this movie from showing up in Movie Recommendations""" + dismiss_recommendation(title=self.title) + + @get + def get_releases(self, country_code='us'): + """Returns all :class:`Release`s for a movie including country, + certification, and release date. + + :param country_code: The 2 character country code to search from + :return: a :const:`list` of :class:`Release` objects + """ + if self._releases is None: + data = yield self.ext + '/releases/{cc}'.format(cc=country_code) + self._releases = [Release(**release) for release in data] + yield self._releases + + @get + def get_translations(self, country_code='us'): + """Returns all :class:`Translation`s for a movie, including language + and translated values for title, tagline and overview. + + :param country_code: The 2 character country code to search from + :return: a :const:`list` of :class:`Translation` objects + """ + if self._translations is None: + data = yield self.ext + '/translations/{cc}'.format( + cc=country_code + ) + self._translations = [Translation(**translation) + for translation in data] + yield self._translations + + def mark_as_seen(self, watched_at=None): + """Add this :class:`Movie`, watched outside of trakt, to your library. + """ + add_to_history(self, watched_at) + + def mark_as_unseen(self): + """Remove this :class:`Movie`, watched outside of trakt, from your + library. + """ + remove_from_history(self) + + def rate(self, rating): + """Rate this :class:`Movie` on trakt. Depending on the current users + settings, this may also send out social updates to facebook, twitter, + tumblr, and path. + """ + rate(self, rating) + + def remove_from_library(self): + """Remove this :class:`Movie` from your library.""" + remove_from_collection(self) + remove_from_collection = remove_from_library + + def remove_from_watchlist(self): + remove_from_watchlist(self) + + def scrobble(self, progress, app_version, app_date): + """Notify trakt that the current user has finished watching a movie. + This commits this :class:`Movie` to the current users profile. You + should use movie/watching prior to calling this method. + + :param progress: % progress, integer 0-100. It is recommended to call + the watching API every 15 minutes, then call the scrobble API near + the end of the movie to lock it in. + :param app_version: Version number of the media center, be as specific + as you can including nightly build number, etc. Used to help debug + your plugin. + :param app_date: Build date of the media center. Used to help debug + your plugin. + """ + return Scrobbler(self, progress, app_version, app_date) + + def checkin(self, app_version, app_date, message="", sharing=None, + venue_id="", venue_name="", delete=False): + """Checkin this :class:`Movie` via the TraktTV API. + + :param app_version:Version number of the media center, be as specific + as you can including nightly build number, etc. Used to help debug + your plugin. + :param app_date: Build date of the media center. Used to help debug + your plugin. + :param message: Message used for sharing. If not sent, it will use the + watching string in the user settings. + :param sharing: Control sharing to any connected social networks. + :param venue_id: Foursquare venue ID. + :param venue_name: Foursquare venue name. + """ + if delete: + delete_checkin() + checkin_media(self, app_version, app_date, message, sharing, venue_id, + venue_name) + + def to_json_singular(self): + return {'movie': dict(title=self.title, + year=self.year, + **self.ids)} + + def to_json(self): + return {'movies': [dict(title=self.title, + year=self.year, + **self.ids)]} + + def __str__(self): + """String representation of a :class:`Movie`""" + return ': {}'.format(unicode_safe(self.title)) + __repr__ = __str__ diff --git a/ext/trakt/people.py b/ext/trakt/people.py new file mode 100644 index 0000000000..fd48cff7f0 --- /dev/null +++ b/ext/trakt/people.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +"""Interfaces to all of the People objects offered by the Trakt.tv API""" +from trakt.core import get +from trakt.sync import search +from trakt.utils import slugify, extract_ids + +__author__ = 'Jon Nappi' +__all__ = ['Person', 'ActingCredit', 'CrewCredit', 'Credits', 'MovieCredits', + 'TVCredits'] + + +class Person(object): + """A Class representing a trakt.tv Person such as an Actor or Director""" + def __init__(self, name, slug=None, **kwargs): + super(Person, self).__init__() + self.name = name + self.biography = self.birthplace = self.tmdb_id = self.birthday = None + self.job = self.character = self._images = self._movie_credits = None + self._tv_credits = None + self.slug = slug or slugify(self.name) + + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + + @classmethod + def search(cls, name, year=None): + """Perform a search for an episode with a title matching *title* + + :param name: The name of the person to search for + :param year: Optional year to limit results to + """ + return search(name, search_type='person', year=year) + + @property + def ext(self): + return 'people/{id}'.format(id=self.slug) + + @property + def ext_full(self): + return self.ext + '?extended=full' + + @property + def images_ext(self): + return self.ext + '?extended=images' + + @property + def ext_movie_credits(self): + return self.ext + '/movies' + + @property + def ext_tv_credits(self): + return self.ext + '/shows' + + @get + def _get(self): + data = yield self.ext_full + self._build(data) + + def _build(self, data): + extract_ids(data) + for key, val in data.items(): + try: + setattr(self, key, val) + except AttributeError as ae: + if not hasattr(self, '_' + key): + raise ae + + @property + @get + def images(self): + """All of the artwork associated with this :class:`Person`""" + if self._images is None: + data = yield self.images_ext + self._images = data.get('images', {}) + yield self._images + + @property + @get + def movie_credits(self): + """Return a collection of movie credits that this :class:`Person` was a + cast or crew member on + """ + if self._movie_credits is None: + data = yield self.ext_movie_credits + self._movie_credits = MovieCredits(**data) + yield self._movie_credits + + @property + @get + def tv_credits(self): + """Return a collection of TV Show credits that this :class:`Person` was + a cast or crew member on + """ + if self._tv_credits is None: + data = yield self.ext_tv_credits + self._tv_credits = TVCredits(**data) + yield self._tv_credits + + def __str__(self): + """String representation of a :class:`Person`""" + return ': {0}'.format(self.name) + __repr__ = __str__ + + +class ActingCredit(object): + """An individual credit for a :class:`Person` who played a character in a + Movie or TV Show + """ + def __init__(self, character, media): + self.character = character + self.media = media + + def __str__(self): + return '<{cls}> {character} - {title}'.format( + cls=self.__class__.__name__, + character=self.character, + title=self.media.title + ) + + __repr__ = __str__ + + +class CrewCredit(object): + """An individual crew credit for a :class:`Person` who had an off-screen + job on a Movie or a TV Show + """ + def __init__(self, job, media): + self.job = job + self.media = media + + def __str__(self): + return '<{cls}> {job} - {title}'.format( + cls=self.__class__.__name__, + job=self.job, + title=self.media.title + ) + + __repr__ = __str__ + + +class Credits(object): + """A base type representing a :class:`Person`'s credits for Movies or TV + Shows + """ + MEDIA_KEY = None + + def __init__(self, **kwargs): + self.cast = [] + self.crew = {} + self._build(**kwargs) + + def _extract_media(self, media): + """Extract the nested media object from an individual Credit resource. + + The *MEDIA_KEY* class attribute must be set by all implementing + subclasses. + """ + raise NotImplementedError + + def _build_cast(self, *cast): + """From the provided JSON array of roles a :class:`Person` has + portrayed, build a detailed list of Acting Credits. + """ + for role in cast: + character = role.get('character') + media = self._extract_media(role) + self.cast.append( + ActingCredit(character=character, media=media) + ) + + def _build_crew(self, **crew): + """From the provided JSON dict of departments and crew credits, build + a dict of Crew Credits + """ + for department, jobs in crew.items(): + self.crew[department] = [ + CrewCredit(job=j.get('job'), + media=self._extract_media(j)) + for j in jobs + ] + + def _build(self, **kwargs): + self._build_cast(*kwargs.get('cast', [])) + self._build_crew(**kwargs.get('crew', {})) + + +class MovieCredits(Credits): + """A collection of cast and crew credits for a Movie""" + MEDIA_KEY = 'movie' + + def _extract_media(self, media): + from trakt.movies import Movie + data = media.get(self.MEDIA_KEY) + return Movie(**data) + + +class TVCredits(Credits): + """A collection of cast and crew credits for a TV Show""" + MEDIA_KEY = 'show' + + def _extract_media(self, media): + from trakt.tv import TVShow + data = media.get(self.MEDIA_KEY) + return TVShow(**data) diff --git a/ext/trakt/sync.py b/ext/trakt/sync.py new file mode 100644 index 0000000000..db6701d434 --- /dev/null +++ b/ext/trakt/sync.py @@ -0,0 +1,520 @@ +# -*- coding: utf-8 -*- +"""This module contains Trakt.tv sync endpoint support functions""" +from datetime import datetime + +from trakt.core import get, post, delete +from trakt.utils import slugify, extract_ids, timestamp + + +__author__ = 'Jon Nappi' +__all__ = ['Scrobbler', 'comment', 'rate', 'add_to_history', 'get_collection', + 'get_watchlist', 'add_to_watchlist', 'remove_from_history', + 'remove_from_watchlist', 'add_to_collection', + 'remove_from_collection', 'search', 'search_by_id'] + + +@post +def comment(media, comment_body, spoiler=False, review=False): + """Add a new comment to a :class:`Movie`, :class:`TVShow`, or + :class:`TVEpisode`. If you add a review, + it needs to be at least 200 words. + + :param media: The media object to post the comment to + :param comment_body: The content of comment + :param spoiler: Boolean flag to indicate whether this comment contains + spoilers + :param review: Boolean flag to determine if this comment is a review (>200 + characters. Note, if *comment_body* is longer than 200 characters, the + review flag will automatically be set to `True` + """ + if not review and len(comment_body) > 200: + review = True + data = dict(comment=comment_body, spoiler=spoiler, review=review) + data.update(media.to_json_singular()) + result = yield 'comments', data + yield result + + +@post +def rate(media, rating, rated_at=None): + """Add a rating from 1 to 10 to a :class:`Movie`, :class:`TVShow`, or + :class:`TVEpisode`. + + :param media: The media object to post a rating to + :param rating: A rating from 1 to 10 for the media item + :param rated_at: A `datetime.datetime` object indicating the time at which + this rating was created + """ + if rated_at is None: + rated_at = datetime.now() + + data = dict(rating=rating, rated_at=timestamp(rated_at)) + data.update(media.ids) + result = yield 'sync/ratings', {media.media_type: [data]} + yield result + + +@post +def add_to_history(media, watched_at=None): + """Add a :class:`Movie`, :class:`TVShow`, or :class:`TVEpisode` to your + watched history. + + :param media: The media object to add to your history + :param watched_at: A `datetime.datetime` object indicating the time at + which this media item was viewed + """ + if watched_at is None: + watched_at = datetime.now() + + data = dict(watched_at=timestamp(watched_at)) + data.update(media.ids) + result = yield 'sync/history', {media.media_type: [data]} + yield result + + +@post +def add_to_watchlist(media): + """Add a :class:`Movie`, :class:`TVShow`, or :class:`TVEpisode` + to your watchlist + :param media: Supports both the PyTrakt :class:`Movie`, + :class:`TVShow`, etc. But also supports passing custom json structures. + """ + from trakt.tv import TVEpisode, TVSeason, TVShow + from trakt.movies import Movie + if isinstance(media, (TVEpisode, TVSeason, TVShow, Movie)): + media_object = media.to_json() + else: + media_object = media + + result = yield 'sync/watchlist', media_object + yield result + + +@post +def remove_from_history(media): + """Remove the specified media object from your history + + :param media: Supports both the PyTrakt :class:`Movie`, + :class:`TVShow`, etc. But also supports passing custom json structures. + """ + from trakt.tv import TVEpisode, TVSeason, TVShow + from trakt.movies import Movie + if isinstance(media, (TVEpisode, TVSeason, TVShow, Movie)): + media_object = media.to_json() + else: + media_object = media + + result = yield 'sync/history/remove', media_object + yield result + + +@post +def remove_from_watchlist(media=None): + """Remove a :class:`TVShow` from your watchlist. + :param media: Supports both the PyTrakt :class:`Movie`, + :class:`TVShow`, etc. But also supports passing custom json structures. + """ + from trakt.tv import TVEpisode, TVSeason, TVShow + from trakt.movies import Movie + if isinstance(media, (TVEpisode, TVSeason, TVShow, Movie)): + media_object = media.to_json() + else: + media_object = media + + result = yield 'sync/watchlist/remove', media_object + yield result + + +@post +def add_to_collection(media): + """Add a :class:`Movie`, :class:`TVShow`, or :class:`TVEpisode + to your collection. + :param media: Supports both the PyTrakt :class:`Movie`, + :class:`TVShow`, etc. But also supports passing custom json structures. + """ + from trakt.tv import TVEpisode, TVSeason, TVShow + from trakt.movies import Movie + if isinstance(media, (TVEpisode, TVSeason, TVShow, Movie)): + media_object = media.to_json() + else: + media_object = media + + result = yield 'sync/collection', media_object + yield result + + +@post +def remove_from_collection(media): + """Remove a :class:`TVShow` from your collection. + :param media: Supports both the PyTrakt :class:`Movie`, + :class:`TVShow`, etc. But also supports passing custom json structures. + """ + from trakt.tv import TVEpisode, TVSeason, TVShow + from trakt.movies import Movie + if isinstance(media, (TVEpisode, TVSeason, TVShow, Movie)): + media_object = media.to_json() + else: + media_object = media + + result = yield 'sync/collection/remove', media_object + yield result + + +def search(query, search_type='movie', year=None, slugify_query=False): + """Perform a search query against all of trakt's media types. + + :param query: Your search string + :param search_type: The type of object you're looking for. Must be one of + 'movie', 'show', 'episode', or 'person' + :param year: This parameter is ignored as it is no longer a part of the + official API. It is left here as a valid arg for backwards + compatability. + :param slugify_query: A boolean indicating whether or not the provided + query should be slugified or not prior to executing the query. + """ + # the new get_search_results expects a list of types, so handle this + # conversion to maintain backwards compatability + if isinstance(search_type, str): + search_type = [search_type] + results = get_search_results(query, search_type, slugify_query) + return [result.media for result in results] + + +@get +def get_search_results(query, search_type=None, slugify_query=False): + """Perform a search query against all of trakt's media types. + + :param query: Your search string + :param search_type: The types of objects you're looking for. Must be + specified as a list of strings containing any of 'movie', 'show', + 'episode', or 'person'. + :param slugify_query: A boolean indicating whether or not the provided + query should be slugified or not prior to executing the query. + """ + # if no search type was specified, then search everything + if search_type is None: + search_type = ['movie', 'show', 'episode', 'person'] + + # If requested, slugify the query prior to running the search + if slugify_query: + query = slugify(query) + + uri = 'search/{type}?query={query}'.format( + query=query, type=','.join(search_type)) + + data = yield uri + + # Need to do imports here to prevent circular imports with modules that + # need to import Scrobblers + results = [] + for media_item in data: + extract_ids(media_item) + result = SearchResult(media_item['type'], media_item['score']) + if media_item['type'] == 'movie': + from trakt.movies import Movie + result.media = Movie(**media_item.pop('movie')) + elif media_item['type'] == 'show': + from trakt.tv import TVShow + result.media = TVShow(**media_item.pop('show')) + elif media_item['type'] == 'episode': + from trakt.tv import TVEpisode + show = media_item.pop('show') + result.media = TVEpisode(show.get('title', None), + **media_item.pop('episode')) + elif media_item['type'] == 'person': + from trakt.people import Person + result.media = Person(**media_item.pop('person')) + results.append(result) + + yield results + + +@get +def search_by_id(query, id_type='imdb', media_type=None, slugify_query=False): + """Perform a search query by using a Trakt.tv ID or other external ID. + + :param query: Your search string, which should be an ID from your source + :param id_type: The source of the ID you're looking for. Must be one of + 'trakt', trakt-movie', 'trakt-show', 'trakt-episode', 'trakt-person', + 'imdb', 'tmdb', or 'tvdb' + :param media_type: The type of media you're looking for. May be one of + 'movie', 'show', 'episode', or 'person', or a comma-separated list of + any combination of those. Null by default, which will return all types + of media that match the ID given. + :param slugify_query: A boolean indicating whether or not the provided + query should be slugified or not prior to executing the query. + """ + valids = ('trakt', 'trakt-movie', 'trakt-show', 'trakt-episode', + 'trakt-person', 'imdb', 'tmdb', 'tvdb') + id_types = {'trakt': 'trakt', 'trakt-movie': 'trakt', + 'trakt-show': 'trakt', 'trakt-episode': 'trakt', + 'trakt-person': 'trakt', 'imdb': 'imdb', 'tmdb': 'tmdb', + 'tvdb': 'tvdb'} + if id_type not in valids: + raise ValueError('search_type must be one of {}'.format(valids)) + source = id_types.get(id_type) + + media_types = {'trakt-movie': 'movie', 'trakt-show': 'show', + 'trakt-episode': 'episode', 'trakt-person': 'person'} + + # If there was no media_type passed in, see if we can guess based off the + # ID source. None is still an option here, as that will return all possible + # types for a given source. + if media_type is None: + media_type = media_types.get(source, None) + + # If requested, slugify the query prior to running the search + if slugify_query: + query = slugify(query) + + # If media_type is still none, don't add it as a parameter to the search + if media_type is None: + uri = 'search/{source}/{query}'.format( + query=query, source=source) + else: + uri = 'search/{source}/{query}?type={media_type}'.format( + query=query, source=source, media_type=media_type) + data = yield uri + + for media_item in data: + extract_ids(media_item) + + results = [] + for d in data: + if 'episode' in d: + from trakt.tv import TVEpisode + show = d.pop('show') + extract_ids(d['episode']) + results.append(TVEpisode(show, **d['episode'])) + elif 'movie' in d: + from trakt.movies import Movie + results.append(Movie(**d.pop('movie'))) + elif 'show' in d: + from trakt.tv import TVShow + results.append(TVShow(**d.pop('show'))) + elif 'person' in d: + from trakt.people import Person + results.append(Person(**d.pop('person'))) + yield results + + +@get +def get_watchlist(list_type=None, sort=None): + """ + Get a watchlist. + + optionally with a filter for a specific item type. + :param list_type: Optional Filter by a specific type. + Possible values: movies, shows, seasons or episodes. + :param sort: Optional sort. Only if the type is also sent. + Possible values: rank, added, released or title. + """ + valid_type = ('movies', 'shows', 'seasons', 'episodes') + valid_sort = ('rank', 'added', 'released', 'title') + + if list_type and list_type not in valid_type: + raise ValueError('list_type must be one of {}'.format(valid_type)) + + if sort and sort not in valid_sort: + raise ValueError('sort must be one of {}'.format(valid_sort)) + + uri = 'sync/watchlist' + if list_type: + uri += '/{}'.format(list_type) + + if list_type and sort: + uri += '/{}'.format(sort) + + data = yield uri + results = [] + for d in data: + if 'episode' in d: + from trakt.tv import TVEpisode + show = d.pop('show') + extract_ids(d['episode']) + results.append(TVEpisode(show, **d['episode'])) + elif 'movie' in d: + from trakt.movies import Movie + results.append(Movie(**d.pop('movie'))) + elif 'show' in d: + from trakt.tv import TVShow + results.append(TVShow(**d.pop('show'))) + + yield results + + +@get +def get_watched(list_type=None, extended=None): + """Return all movies or shows a user has watched sorted by most plays. + + :param list_type: Optional Filter by a specific type. + Possible values: movies, shows, seasons or episodes. + :param extended: Optional value for requesting extended information. + """ + valid_type = ('movies', 'shows', 'seasons', 'episodes') + + if list_type and list_type not in valid_type: + raise ValueError('list_type must be one of {}'.format(valid_type)) + + uri = 'sync/watchlist' + if list_type: + uri += '/{}'.format(list_type) + + if list_type == 'shows' and extended: + uri += '?extended={extended}'.format(extended=extended) + + data = yield uri + results = [] + for d in data: + if 'movie' in d: + from trakt.movies import Movie + results.append(Movie(**d.pop('movie'))) + elif 'show' in d: + from trakt.tv import TVShow + results.append(TVShow(**d.pop('show'))) + + yield results + + +@get +def get_collection(list_type=None, extended=None): + """ + Get all collected items in a user's collection. + + A collected item indicates availability to watch digitally + or on physical media. + + :param list_type: Optional Filter by a specific type. + Possible values: movies or shows. + :param extended: Optional value for requesting extended information. + """ + valid_type = ('movies', 'shows') + + if list_type and list_type not in valid_type: + raise ValueError('list_type must be one of {}'.format(valid_type)) + + uri = 'sync/watchlist' + if list_type: + uri += '/{}'.format(list_type) + + if extended: + uri += '?extended={extended}'.format(extended=extended) + + data = yield uri + results = [] + for d in data: + if 'movie' in d: + from trakt.movies import Movie + results.append(Movie(**d.pop('movie'))) + elif 'show' in d: + from trakt.tv import TVShow + results.append(TVShow(**d.pop('show'))) + + yield results + + +@post +def checkin_media(media, app_version, app_date, message="", sharing=None, + venue_id="", venue_name=""): + """Checkin a media item. + """ + payload = dict(app_version=app_version, app_date=app_date, sharing=sharing, + message=message, venue_id=venue_id, venue_name=venue_name) + payload.update(media.to_json_singular()) + result = yield "checkin", payload + yield result + + +@delete +def delete_checkin(): + yield "checkin" + + +class Scrobbler(object): + """Scrobbling is a seemless and automated way to track what you're watching + in a media center. This class allows the media center to easily send + events that correspond to starting, pausing, stopping or finishing + a movie or episode. + """ + + def __init__(self, media, progress, app_version, app_date): + """Create a new :class:`Scrobbler` instance + + :param media: The media object you're scrobbling. Must be either a + :class:`Movie` or :class:`TVEpisode` type + :param progress: The progress made through *media* at the time of + creation + :param app_version: The media center application version + :param app_date: The date that *app_version* was released + """ + super(Scrobbler, self).__init__() + self.progress, self.version = progress, app_version + self.media, self.date = media, app_date + if self.progress > 0: + self.start() + + def start(self): + """Start scrobbling this :class:`Scrobbler`'s *media* object""" + self._post('scrobble/start') + + def pause(self): + """Pause the scrobbling of this :class:`Scrobbler`'s *media* object""" + self._post('scrobble/pause') + + def stop(self): + """Stop the scrobbling of this :class:`Scrobbler`'s *media* object""" + self._post('scrobble/stop') + + def finish(self): + """Complete the scrobbling this :class:`Scrobbler`'s *media* object""" + if self.progress < 80.0: + self.progress = 100.0 + self.stop() + + def update(self, progress): + """Update the scobbling progress of this :class:`Scrobbler`'s *media* + object + """ + self.progress = progress + self.start() + + @post + def _post(self, uri): + """Handle actually posting the scrobbling data to trakt + + :param uri: The uri to post to + """ + payload = dict(progress=self.progress, app_version=self.version, + date=self.date) + payload.update(self.media.to_json_singular()) + yield uri, payload + + def __enter__(self): + """Context manager support for `with Scrobbler` syntax. Begins + scrobbling the :class:`Scrobbler`'s *media* object + """ + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """Context manager support for `with Scrobbler` syntax. Completes + scrobbling the :class:`Scrobbler`'s *media* object + """ + self.finish() + + +class SearchResult(object): + """A SearchResult is an individual result item from the trakt.tv search + API. It wraps a single media entity whose type is indicated by the type + field. + """ + def __init__(self, type, score, media=None): + """Create a new :class:`SearchResult` instance + + :param type: The type of media object contained in this result. + :param score: The search result relevancy score of this item. + :param media: The wrapped media item returned by a search. + """ + self.type = type + self.score = score + self.media = media diff --git a/ext/trakt/tv.py b/ext/trakt/tv.py new file mode 100644 index 0000000000..759972ad46 --- /dev/null +++ b/ext/trakt/tv.py @@ -0,0 +1,884 @@ +# -*- coding: utf-8 -*- +"""Interfaces to all of the TV objects offered by the Trakt.tv API""" +from collections import namedtuple +from datetime import datetime, timedelta +from trakt.core import Airs, Alias, Comment, Genre, delete, get +from trakt.errors import NotFoundException +from trakt.sync import (Scrobbler, rate, comment, add_to_collection, + add_to_watchlist, add_to_history, remove_from_history, + remove_from_collection, remove_from_watchlist, search, + checkin_media, delete_checkin) +from trakt.utils import slugify, extract_ids, airs_date, unicode_safe +from trakt.people import Person + +__author__ = 'Jon Nappi' +__all__ = ['dismiss_recommendation', 'get_recommended_shows', 'genres', + 'popular_shows', 'trending_shows', 'updated_shows', + 'recommended_shows', 'played_shows', 'watched_shows', + 'collected_shows', 'anticipated_shows', 'TVShow', 'TVEpisode', + 'TVSeason', 'Translation'] + + +Translation = namedtuple('Translation', ['title', 'overview', 'language']) + + +@delete +def dismiss_recommendation(title=None): + """Dismiss the show matching the specified criteria from showing up in + recommendations. + """ + yield 'recommendations/shows/{title}'.format(title=title) + + +@get +def get_recommended_shows(page=1, limit=10): + """Get a list of :class:`TVShow`'s recommended based on your watching + history and your friends. Results are returned with the top recommendation + first. + """ + data = yield 'recommendations/shows?page={page}&limit={limit}'.format( + page=page, limit=limit + ) + yield [TVShow(**show) for show in data] + + +@get +def genres(): + """A list of all possible :class:`TVShow` Genres""" + data = yield 'genres/shows' + yield [Genre(g['name'], g['slug']) for g in data] + + +@get +def popular_shows(page=1, limit=10, extended=None): + uri = 'shows/popular?page={page}&limit={limit}'.format( + page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show) for show in data] + + +@get +def trending_shows(page=1, limit=10, extended=None): + """All :class:`TVShow`'s being watched right now""" + uri = 'shows/trending?page={page}&limit={limit}'.format( + page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +@get +def updated_shows(timestamp=None, page=1, limit=10, extended=None): + """All :class:`TVShow`'s updated since *timestamp* (PST). To establish a + baseline timestamp, you can use the server/time method. It's recommended to + store the timestamp so you can be efficient in using this method. + """ + y_day = datetime.now() - timedelta(1) + ts = timestamp or int(y_day.strftime('%s')) * 1000 + uri = 'shows/updates/{start_date}?page={page}&limit={limit}'.format( + start_date=ts, page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show) for show in data] + + +@get +def recommended_shows(time_period='weekly', page=1, limit=10, extended=None): + """The most recommended shows in the specified time period, + defaulting to weekly. + All stats are relative to the specific time period.""" + valid_time_period = ('daily', 'weekly', 'monthly', 'yearly', 'all') + if time_period not in valid_time_period: + raise ValueError('time_period must be one of {}'.format( + valid_time_period + )) + + uri = 'shows/recommended/{time_period}?page={page}&limit={limit}'.format( + time_period=time_period, page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +@get +def played_shows(time_period='weekly', page=1, limit=10, extended=None): + """the most played shows. + (a single user can watch multiple episodes multiple times) + shows in the specified time period, + defaulting to weekly. + All stats are relative to the specific time period.""" + valid_time_period = ('daily', 'weekly', 'monthly', 'yearly', 'all') + if time_period not in valid_time_period: + raise ValueError('time_period must be one of {}'.format( + valid_time_period + )) + + uri = 'shows/played/{time_period}?page={page}&limit={limit}'.format( + time_period=time_period, page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +@get +def watched_shows(time_period='weekly', page=1, limit=10, extended=None): + """Return most watched (unique users) shows in the specified time period. + + Defaulting to weekly. + All stats are relative to the specific time period.""" + valid_time_period = ('daily', 'weekly', 'monthly', 'yearly', 'all') + if time_period not in valid_time_period: + raise ValueError('time_period must be one of {}'.format( + valid_time_period + )) + + uri = 'shows/watched/{time_period}?page={page}&limit={limit}'.format( + time_period=time_period, page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +@get +def collected_shows(time_period='weekly', page=1, limit=10, extended=None): + """Return most collected (unique users) shows in the specified time period. + + Defaulting to weekly. + All stats are relative to the specific time period.""" + valid_time_period = ('daily', 'weekly', 'monthly', 'yearly', 'all') + if time_period not in valid_time_period: + raise ValueError('time_period must be one of {}'.format( + valid_time_period + )) + + uri = 'shows/collected/{time_period}?page={page}&limit={limit}'.format( + time_period=time_period, page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +@get +def anticipated_shows(page=1, limit=10, extended=None): + """ + Return most anticipated shows based on the number of lists + a show appears on. + """ + uri = 'shows/anticipated?page={page}&limit={limit}'.format( + page=page, limit=limit + ) + if extended: + uri += '&extended={extended}'.format(extended=extended) + data = yield uri + yield [TVShow(**show['show']) for show in data] + + +class TVShow(object): + """A Class representing a TV Show object.""" + + def __init__(self, title='', slug=None, **kwargs): + super(TVShow, self).__init__() + self.media_type = 'shows' + self.top_watchers = self.top_episodes = self.year = self.tvdb = None + self.imdb = self.genres = self.certification = self.network = None + self.trakt = self.tmdb = self._aliases = self._comments = None + self._images = self._people = self._ratings = self._translations = None + self._seasons = None + self._last_episode = self._next_episode = None + self.title = title + self.slug = slug or slugify(self.title) + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + + @classmethod + def search(cls, title, year=None): + """Perform a search for the specified *title*. + + :param title: The title to search for + """ + return search(title, search_type='show', year=year) + + @get + def _get(self): + data = yield self.ext_full + data['first_aired'] = airs_date(data['first_aired']) + data['airs'] = Airs(**data['airs']) + self._build(data) + + def _build(self, data): + extract_ids(data) + for key, val in data.items(): + if hasattr(self, '_' + key): + setattr(self, '_' + key, val) + else: + setattr(self, key, val) + + @property + def ext(self): + return 'shows/{slug}'.format(slug=self.slug) + + @property + def ext_full(self): + return self.ext + '?extended=full' + + @property + def images_ext(self): + """Uri to retrieve additional image information.""" + return self.ext + '?extended=images' + + @property + @get + def aliases(self): + """A list of :class:`Alias` objects representing all of the other + titles that this :class:`TVShow` is known by, and the countries where + they go by their alternate titles + """ + if self._aliases is None: + data = yield (self.ext + '/aliases') + self._aliases = [Alias(**alias) for alias in data] + yield self._aliases + + @property + def cast(self): + """All of the cast members that worked on this :class:`TVShow`""" + return [p for p in self.people if getattr(p, 'character')] + + @property + @get + def comments(self): + """All comments (shouts and reviews) for this :class:`TVShow`. Most + recent comments returned first. + """ + # TODO (jnappi) Pagination + from .users import User + + data = yield (self.ext + '/comments') + self._comments = [] + for com in data: + user = User(**com.pop('user')) + self._comments.append(Comment(user=user, **com)) + yield self._comments + + @property + @get + def progress(self): + """ + collection progress for a show including details on all aired + seasons and episodes. + + The next_episode will be the next episode the user should collect, + if there are no upcoming episodes it will be set to null. + """ + yield (self.ext + '/progress/collection') + + @property + def crew(self): + """All of the crew members that worked on this :class:`TVShow`""" + return [p for p in self.people if getattr(p, 'job')] + + @property + def ids(self): + """Accessor to the trakt, imdb, and tmdb ids, as well as the trakt.tv + slug + """ + return {'ids': { + 'trakt': self.trakt, 'slug': self.slug, 'imdb': self.imdb, + 'tmdb': self.tmdb, 'tvdb': self.tvdb + }} + + @property + @get + def images(self): + """All of the artwork associated with this :class:`TVShow`""" + if self._images is None: + data = yield self.images_ext + self._images = data.get('images', {}) + yield self._images + + @property + @get + def people(self): + """A :const:`list` of all of the :class:`People` involved in this + :class:`TVShow`, including both cast and crew + """ + if self._people is None: + data = yield (self.ext + '/people') + crew = data.get('crew', {}) + cast = [] + for c in data.get('cast', []): + person = c.pop('person') + character = c.pop('character') + cast.append(Person(character=character, **person)) + + _crew = [] + for key in crew: + for department in crew.get(key): # lists + person = department.get('person') + person.update({'job': department.get('job')}) + _crew.append(Person(**person)) + self._people = cast + _crew + yield self._people + + @property + @get + def ratings(self): + """Ratings (between 0 and 10) and distribution for a movie.""" + if self._ratings is None: + self._ratings = yield (self.ext + '/ratings') + yield self._ratings + + @property + @get + def related(self): + """The top 10 :class:`TVShow`'s related to this :class:`TVShow`""" + data = yield (self.ext + '/related') + shows = [] + for show in data: + shows.append(TVShow(**show)) + yield shows + + @property + @get + def seasons(self): + """A list of :class:`TVSeason` objects representing all of this show's + seasons + """ + if self._seasons is None: + data = yield (self.ext + '/seasons?extended=full') + self._seasons = [] + for season in data: + extract_ids(season) + self._seasons.append(TVSeason(self.title, + season['number'], **season)) + yield self._seasons + + @property + @get + def last_episode(self): + """Returns the most recently aired :class:`TVEpisode`. If no episode + is found, `None` will be returned. + """ + if self._last_episode is None: + data = yield (self.ext + '/last_episode?extended=full') + self._last_episode = data and TVEpisode(show=self.title, **data) + yield self._last_episode + + @property + @get + def next_episode(self): + """Returns the next scheduled to air :class:`TVEpisode`. If no episode + is found, `None` will be returned. + """ + if self._next_episode is None: + data = yield (self.ext + '/next_episode?extended=full') + self._next_episode = data and TVEpisode(show=self.title, **data) + yield self._next_episode + + @property + @get + def watching_now(self): + """A list of all :class:`User`'s watching a movie.""" + from .users import User + data = yield self.ext + '/watching' + users = [] + for user in data: + users.append(User(**user)) + yield users + + def add_to_library(self): + """Add this :class:`TVShow` to your library.""" + return add_to_collection(self) + + add_to_collection = add_to_library + + def add_to_watchlist(self): + """Add this :class:`TVShow` to your watchlist""" + return add_to_watchlist(self) + + def comment(self, comment_body, spoiler=False, review=False): + """Add a comment (shout or review) to this :class:`Move` on trakt.""" + return comment(self, comment_body, spoiler, review) + + def dismiss(self): + """Dismiss this movie from showing up in Movie Recommendations""" + dismiss_recommendation(title=self.title) + + @get + def get_translations(self, country_code='us'): + """Returns all :class:`Translation`'s for a movie, including language + and translated values for title, tagline and overview. + + :param country_code: The 2 character country code to search from + :return: a :const:`list` of :class:`Translation` objects + """ + if self._translations is None: + data = yield self.ext + '/translations/{cc}'.format( + cc=country_code + ) + self._translations = [Translation(**translation) + for translation in data] + yield self._translations + + def mark_as_seen(self, watched_at=None): + """Add this :class:`TVShow`, watched outside of trakt, to your library. + """ + return add_to_history(self, watched_at) + + def mark_as_unseen(self): + """Remove this :class:`TVShow`, watched outside of trakt, from your + library. + """ + return remove_from_history(self) + + def rate(self, rating): + """Rate this :class:`TVShow` on trakt. Depending on the current users + settings, this may also send out social updates to facebook, twitter, + tumblr, and path. + """ + return rate(self, rating) + + def remove_from_library(self): + """Remove this :class:`TVShow` from your library.""" + return remove_from_collection(self) + + remove_from_collection = remove_from_library + + def remove_from_watchlist(self): + return remove_from_watchlist(self) + + def to_json_singular(self): + return {'show': { + 'title': self.title, 'year': self.year, 'ids': self.ids + }} + + def to_json(self): + return {'shows': [{ + 'title': self.title, 'year': self.year, 'ids': self.ids + }]} + + def __str__(self): + """Return a string representation of a :class:`TVShow`""" + return ' {}'.format(unicode_safe(self.title)) + + __repr__ = __str__ + + +class TVSeason(object): + """Container for TV Seasons""" + + def __init__(self, show, season=1, slug=None, **kwargs): + super(TVSeason, self).__init__() + self.show = show + self.season = season + self.slug = slug or slugify(show) + self._episodes = self._comments = self._ratings = None + self.ext = 'shows/{id}/seasons/{season}'.format(id=self.slug, + season=season) + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + + @get + def _get(self): + """Handle getting this :class:`TVSeason`'s data from trakt and building + our attributes from the returned data + """ + data = yield self.ext + self._build(data) + + def _build(self, data): + """Build this :class:`TVSeason` object with the data in *data*""" + # only try to build our episodes if we got a list of episodes, not a + # dict of season data + if isinstance(data, list): + self._episodes = [TVEpisode(show=self.show, **ep) for ep in data] + else: + for key, val in data.items(): + try: + setattr(self, key, val) + except AttributeError: + setattr(self, '_'+key, val) + + @property + @get + def comments(self): + """All comments (shouts and reviews) for this :class:`TVSeason`. Most + recent comments returned first. + """ + # TODO (jnappi) Pagination + from .users import User + + data = yield (self.ext + '/comments') + self._comments = [] + for com in data: + user = User(**com.pop('user')) + comment = Comment(user=user, **com) + self._comments.append(comment) + yield self._comments + + @property + def episodes(self): + """A list of :class:`TVEpisode` objects representing all of the + Episodes in this :class:`TVSeason`. Because there is no "Get all + episodes for a season" endpoint on the trakt api + """ + if self._episodes is None: + self._episodes = [] + index = 1 + while True: # Dangerous? Perhaps, but it works + try: + ep = self._episode_getter(index) + self._episodes.append(ep) + except (NotFoundException, TypeError): + break + index += 1 + return self._episodes + + @get + def _episode_getter(self, episode): + """Recursive episode getter generator. Will attempt to get the + specified episode for this season, and if the requested episode wasn't + found, then we return :const:`None` to indicate to the `episodes` + property that we've already yielded all valid episodes for this season. + + :param episode: An int corresponding to the number of the episode + we're trying to retrieve + """ + episode_extension = '/episodes/{}?extended=full'.format(episode) + try: + data = yield (self.ext + episode_extension) + yield TVEpisode(show=self.show, **data) + except NotFoundException: + yield None + + @property + @get + def ratings(self): + """Ratings (between 0 and 10) and distribution for a movie.""" + if self._ratings is None: + self._ratings = yield (self.ext + '/ratings') + yield self._ratings + + @property + @get + def watching_now(self): + """A list of all :class:`User`'s watching a movie.""" + from .users import User + + data = yield self.ext + '/watching' + users = [] + for user in data: + users.append(User(**user)) + yield users + + def add_to_library(self): + """Add this :class:`TVSeason` to your library.""" + add_to_collection(self) + + add_to_collection = add_to_library + + def remove_from_library(self): + """Remove this :class:`TVSeason` from your library.""" + remove_from_collection(self) + + remove_from_collection = remove_from_library + + def to_json(self): + """Return this :class:`TVSeason` as a Trakt consumable API blob""" + # I hate that this extra lookup needs to happen here, but I can't see + # any other way of getting around not having the data on the show... + show_obj = TVShow(self.slug).to_json() + show_obj.update({'seasons': [{'number': self.season}]}) + return {'shows': [show_obj]} + + def __str__(self): + title = [':', self.show, 'Season', self.season] + title = map(str, title) + return ' '.join(title) + + def __len__(self): + return len(self._episodes) + + __repr__ = __str__ + + +class TVEpisode(object): + """Container for TV Episodes""" + + def __init__(self, show, season, number=-1, **kwargs): + super(TVEpisode, self).__init__() + self.media_type = 'episodes' + self.show = show + self.season = season + self.number = number + self.overview = self.title = self.year = self.number_abs = None + self.first_aired = self.last_updated = None + self.trakt = self.tmdb = self.tvdb = self.imdb = None + self.tvrage = self._stats = self._images = self._comments = None + self._translations = self._ratings = None + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + self.episode = self.number # Backwards compatability + + @get + def _get(self): + """Handle getting this :class:`TVEpisode`'s data from trakt and + building our attributes from the returned data + """ + data = yield self.ext_full + self._build(data) + + def _build(self, data): + """Build this :class:`TVEpisode` object with the data in *data*""" + extract_ids(data) + for key, val in data.items(): + if hasattr(self, '_' + key): + setattr(self, '_' + key, val) + else: + setattr(self, key, val) + + @property + @get + def comments(self): + """All comments (shouts and reviews) for this :class:`TVEpisode`. Most + recent comments returned first. + """ + # TODO (jnappi) Pagination + from .users import User + + data = yield (self.ext + '/comments') + self._comments = [] + for com in data: + user = User(**com.pop('user')) + self._comments.append(Comment(user=user, **com)) + yield self._comments + + @property + def ext(self): + return 'shows/{id}/seasons/{season}/episodes/{episode}'.format( + id=slugify(self.show), season=self.season, episode=self.number + ) + + @property + def ext_full(self): + return self.ext + '?extended=full' + + @property + def images_ext(self): + """Uri to retrieve additional image information""" + return self.ext + '?extended=images' + + @classmethod + def search(cls, title, year=None): + """Perform a search for an episode with a title matching *title* + + :param title: The title to search for + :param year: Optional year to limit results to + """ + return search(title, search_type='episode', year=year) + + @property + def ids(self): + """Accessor to the trakt, imdb, and tmdb ids, as well as the trakt.tv + slug + """ + return {'ids': { + 'trakt': self.trakt, 'imdb': self.imdb, 'tmdb': self.tmdb + }} + + @property + @get + def images(self): + """All of the artwork associated with this :class:`TVEpisode`""" + if self._images is None: + data = yield self.images_ext + self._images = data.get('images', {}) + yield self._images + + @property + def first_aired_date(self): + """Python datetime object representation of the first_aired date of + this :class:`TVEpisode` + """ + return airs_date(self.first_aired) + + @property + def first_aired_end_time(self): + """Python datetime object representing the corresponding end time of + the first_aired date of this episode + """ + return self.end_time_from_custom_start(start_date=None) + + def end_time_from_custom_start(self, start_date=None): + """Calculate a python datetime object representing the calculated end + time of an episode from the given start_date. ie, start_date + + runtime. + + :param start_date: a datetime instance indicating the start date of a + given airing of this episode. Defaults to the first_aired_date of this + episode. + """ + if start_date is None: + start_date = self.first_aired_date + + # create a timedelta instance for the runtime of the episode + runtime = timedelta(minutes=self.runtime) + + # calculate the end time as the difference between the first_aired_date + # and the runtime timedelta + return start_date + runtime + + @property + @get + def ratings(self): + """Ratings (between 0 and 10) and distribution for a movie.""" + if self._ratings is None: + self._ratings = yield (self.ext + '/ratings') + yield self._ratings + + @property + @get + def watching_now(self): + """A list of all :class:`User`'s watching a movie.""" + from .users import User + + data = yield self.ext + '/watching' + users = [] + for user in data: + users.append(User(**user)) + yield users + + def get_description(self): + """backwards compatible function that returns this :class:`TVEpisode`'s + overview + '""" + return self.overview + + def rate(self, rating): + """Rate this :class:`TVEpisode` on trakt. Depending on the current users + settings, this may also send out social updates to facebook, twitter, + tumblr, and path. + """ + rate(self, rating) + + def add_to_library(self): + """Add this :class:`TVEpisode` to your Trakt.tv library""" + add_to_collection(self) + + add_to_collection = add_to_library + + def add_to_watchlist(self): + """Add this :class:`TVEpisode` to your watchlist""" + add_to_watchlist(self) + + def mark_as_seen(self, watched_at=None): + """Mark this episode as seen""" + add_to_history(self, watched_at) + + def mark_as_unseen(self): + """Remove this :class:`TVEpisode` from your list of watched episodes""" + remove_from_history(self) + + def remove_from_library(self): + """Remove this :class:`TVEpisode` from your library""" + remove_from_collection(self) + + remove_from_collection = remove_from_library + + def remove_from_watchlist(self): + """Remove this :class:`TVEpisode` from your watchlist""" + remove_from_watchlist(self) + + def comment(self, comment_body, spoiler=False, review=False): + """Add a comment (shout or review) to this :class:`TVEpisode` on trakt. + """ + comment(self, comment_body, spoiler, review) + + def scrobble(self, progress, app_version, app_date): + """Scrobble this :class:`TVEpisode` via the TraktTV Api + + :param progress: % progress, integer 0-100. It is recommended to call + the watching API every 15 minutes, then call the scrobble API near + the end of the movie to lock it in. + :param app_version: Version number of the media center, be as specific + as you can including nightly build number, etc. Used to help debug + your plugin. + :param app_date: Build date of the media center. Used to help debug + your plugin. + """ + return Scrobbler(self, progress, app_version, app_date) + + def checkin(self, app_version, app_date, message="", sharing=None, + venue_id="", venue_name="", delete=False): + """Checkin this :class:`TVEpisode` via the TraktTV API + + :param app_version:Version number of the media center, be as specific + as you can including nightly build number, etc. Used to help debug + your plugin. + :param app_date: Build date of the media center. Used to help debug + your plugin. + :param message: Message used for sharing. If not sent, it will use the + watching string in the user settings. + :param sharing: Control sharing to any connected social networks. + :param venue_id: Foursquare venue ID. + :param venue_name: Foursquare venue name. + """ + if delete: + delete_checkin() + checkin_media(self, app_version, app_date, message, sharing, venue_id, + venue_name) + + def to_json_singular(self): + """Return this :class:`TVEpisode` as a trakt recognizable JSON object + """ + return { + 'episode': { + 'ids': { + 'trakt': self.trakt + } + } + } + + def to_json(self): + """Return this :class:`TVEpisode` as a trakt recognizable JSON object + """ + return { + 'episodes': [{ + 'ids': { + 'trakt': self.trakt + } + }] + } + + def __str__(self): + return ': {} S{}E{} {}'.format(self.show, self.season, + self.number, + unicode_safe(self.title)) + __repr__ = __str__ diff --git a/ext/trakt/users.py b/ext/trakt/users.py new file mode 100644 index 0000000000..3c7c0610e0 --- /dev/null +++ b/ext/trakt/users.py @@ -0,0 +1,498 @@ +# -*- coding: utf-8 -*- +"""Interfaces to all of the User objects offered by the Trakt.tv API""" +from collections import namedtuple +from trakt.core import get, post, delete +from trakt.movies import Movie +from trakt.people import Person +from trakt.tv import TVShow, TVSeason, TVEpisode +from trakt.utils import slugify, extract_ids, unicode_safe + +__author__ = 'Jon Nappi' +__all__ = ['User', 'UserList', 'Request', 'follow', 'get_all_requests', + 'get_user_settings', 'unfollow'] + + +class Request(namedtuple('Request', ['id', 'requested_at', 'user'])): + __slots__ = () + + @post + def approve(self): + yield 'users/requests/{id}'.format(id=self.id) + + @delete + def deny(self): + yield 'users/requests/{id}'.format(id=self.id) + + +@post +def follow(user_name): + """Follow a user with *user_name*. If the user has a protected profile, the + follow request will be in a pending state. If they have a public profile, + they will be followed immediately. + """ + yield 'users/{username}/follow'.format(username=slugify(user_name)) + + +@get +def get_all_requests(): + """Get a list of all follower requests including the timestamp when the + request was made. Use the approve and deny methods to manage each request. + """ + data = yield 'users/requests' + request_list = [] + for request in data: + request['user'] = User(**request.pop('user')) + request_list.append(Request(**request)) + yield request_list + + +@get +def get_user_settings(): + """The currently authenticated user's settings""" + data = yield 'users/settings' + yield data + + +@delete +def unfollow(user_name): + """Unfollow a user you're currently following with a username of *user_name* + """ + yield 'users/{username}/follow'.format(username=slugify(user_name)) + + +class UserList(namedtuple('UserList', ['name', 'description', 'privacy', + 'display_numbers', 'allow_comments', + 'sort_by', 'sort_how', 'created_at', + 'updated_at', 'item_count', + 'comment_count', 'likes', 'trakt', + 'slug', 'user', 'creator'])): + """A list created by a Trakt.tv :class:`User`""" + + def __init__(self, *args, **kwargs): + super(UserList, self).__init__() + self._items = list() + + def __iter__(self, *args, **kwargs): + """Iterate over the items in this user list""" + return self._items.__iter__(*args, **kwargs) + + @classmethod + @post + def create(cls, name, creator, description=None, privacy='private', + display_numbers=False, allow_comments=True): + """Create a new custom class:`UserList`. *name* is the only required + field, but the other info is recommended. + + :param name: Name of the list. + :param description: Description of this list. + :param privacy: Valid values are 'private', 'friends', or 'public' + :param display_numbers: Bool, should each item be numbered? + :param allow_comments: Bool, are comments allowed? + """ + args = {'name': name, 'privacy': privacy, + 'display_numbers': display_numbers, + 'allow_comments': allow_comments} + if description is not None: + args['description'] = description + data = yield 'users/{user}/lists'.format(user=slugify(creator)), args + extract_ids(data) + yield UserList(creator=creator, user=creator, **data) + + @classmethod + @get + def _get(cls, title, creator): + """Returns a single custom :class:`UserList` + + :param title: Name of the list. + """ + data = yield 'users/{user}/lists/{id}'.format(user=slugify(creator), + id=slugify(title)) + extract_ids(data) + ulist = UserList(creator=creator, **data) + ulist.get_items() + + yield ulist + + @get + def get_items(self): + """A list of the list items using class instances + instance types: movie, show, season, episode, person + + """ + + data = yield 'users/{user}/lists/{id}/items'.format( + user=slugify(self.creator), id=self.slug) + + for item in data: + # match list item type + if 'type' not in item: + continue + item_type = item['type'] + item_data = item.pop(item_type) + extract_ids(item_data) + if item_type == 'movie': + self._items.append(Movie(item_data['title'], item_data['year'], + item_data['slug'])) + elif item_type == 'show': + self._items.append(TVShow(item_data['title'], + item_data['slug'])) + elif item_type == 'season': + show_data = item.pop('show') + extract_ids(show_data) + season = TVSeason(show_data['title'], item_data['number'], + show_data['slug']) + self._items.append(season) + elif item_type == 'episode': + show_data = item.pop('show') + extract_ids(show_data) + episode = TVEpisode(show_data['title'], item_data['season'], + item_data['number']) + self._items.append(episode) + elif item_type == 'person': + self._items.append(Person(item_data['name'], + item_data['slug'])) + + yield self._items + + @post + def add_items(self, *items): + """Add *items* to this :class:`UserList`, where items is an iterable""" + movies = [m.ids for m in items if isinstance(m, Movie)] + shows = [s.ids for s in items if isinstance(s, TVShow)] + people = [p.ids for p in items if isinstance(p, Person)] + self._items = items + args = {'movies': movies, 'shows': shows, 'people': people} + uri = 'users/{user}/lists/{id}/items'.format( + user=slugify(self.creator), id=self.trakt) + yield uri, args + + @delete + def delete_list(self): + """Delete this :class:`UserList`""" + yield 'users/{user}/lists/{id}'.format(user=slugify(self.creator), + id=self.trakt) + + @post + def like(self): + """Like this :class:`UserList`. Likes help determine popular lists. + Only one like is allowed per list per user. + """ + uri = 'users/{user}/lists/{id}/like' + yield uri.format(user=slugify(self.creator), id=self.trakt), None + + @post + def remove_items(self, *items): + """Remove *items* to this :class:`UserList`, where items is an iterable + """ + movies = [m.ids for m in items if isinstance(m, Movie)] + shows = [s.ids for s in items if isinstance(s, TVShow)] + people = [p.ids for p in items if isinstance(p, Person)] + self._items = items + args = {'movies': movies, 'shows': shows, 'people': people} + uri = 'users/{user}/lists/{id}/items/remove'.format( + user=slugify(self.creator), id=self.trakt) + yield uri, args + + @delete + def unlike(self): + """Remove a like on this :class:`UserList`.""" + uri = 'users/{username}/lists/{id}/like' + yield uri.format(username=slugify(self.creator), id=self.trakt) + + +class User(object): + """A Trakt.tv User""" + def __init__(self, username, **kwargs): + super(User, self).__init__() + self.username = username + self._calendar = self._last_activity = self._watching = None + self._movies = self._movie_collection = self._movies_watched = None + self._shows = self._show_collection = self._shows_watched = None + self._lists = self._followers = self._following = self._friends = None + self._collected = self._watched_shows = self._episode_ratings = None + self._show_ratings = self._movie_ratings = self._watched_movies = None + self._episode_watchlist = self._show_watchlist = None + self._movie_watchlist = None + + self._settings = None + + if len(kwargs) > 0: + self._build(kwargs) + else: + self._get() + + @get + def _get(self): + """Get this :class:`User` from the trakt.tv API""" + data = yield 'users/{username}'.format(username=slugify(self.username)) + self._build(data) + + def _build(self, data): + """Build our this :class:`User` object""" + for key, val in data.items(): + setattr(self, key, val) + + @property + @get + def followers(self): + """A list of all followers including the since timestamp which is when + the relationship began. Protected users won't return any data unless + you are friends. Any friends of the main user that are protected won't + display data either. + """ + if self._followers is None: + data = yield 'users/{user}/followers'.format( + user=slugify(self.username)) + self._followers = [] + for user in data: + user_data = user.pop('user') + date = user.pop('followed_at') + self._followers.append(User(followed_at=date, **user_data)) + yield self._followers + + @property + @get + def following(self): + """A list of all user's this :class:`User` follows including the since + timestamp which is when the relationship began. Protected users won't + return any data unless you are friends. Any friends of the main user + that are protected won't display data either. + """ + if self._following is None: + data = yield 'users/{user}/following'.format( + user=slugify(self.username)) + self._following = [] + for user in data: + user_data = user.pop('user') + date = user.pop('followed_at') + self._following.append(User(followed_at=date, **user_data)) + yield self._following + + @property + @get + def friends(self): + """A list of this :class:`User`'s friends (a 2 way relationship where + each user follows the other) including the since timestamp which is + when the friendship began. Protected users won't return any data unless + you are friends. Any friends of the main user that are protected won't + display data either. + """ + if self._friends is None: + self._friends = [] + data = yield 'users/{user}/friends'.format( + user=slugify(self.username)) + for user in data: + user_data = user.pop('user') + date = user.pop('friends_at') + self._friends.append(User(followed_at=date, **user_data)) + yield self._friends + + @property + @get + def lists(self): + """All custom lists for this :class:`User`. Protected :class:`User`'s + won't return any data unless you are friends. To view your own private + lists, you will need to authenticate as yourself. + """ + if self._lists is None: + data = yield 'users/{username}/lists'.format( + username=slugify(self.username)) + for ul in data: + if "user" in ul: + # user will be replaced with the self User object + del ul["user"] + self._lists = [UserList(creator=slugify(self.username), user=self, + **extract_ids(ul)) for ul in data] + yield self._lists + + @property + @get + def watchlist_shows(self): + """Returns all watchlist shows of :class:`User`. + """ + if self._show_watchlist is None: + data = yield 'users/{username}/watchlist/shows'.format( + username=slugify(self.username), + ) + self._show_watchlist = [] + for show in data: + show_data = show.pop('show') + extract_ids(show_data) + show_data.update(show) + self._show_watchlist.append(TVShow(**show_data)) + yield self._show_watchlist + yield self._show_watchlist + + @property + @get + def watchlist_movies(self): + """Returns all watchlist movies of :class:`User`. + """ + if self._movie_watchlist is None: + data = yield 'users/{username}/watchlist/movies'.format( + username=slugify(self.username), + ) + self._movie_watchlist = [] + for movie in data: + mov = movie.pop('movie') + extract_ids(mov) + self._movie_watchlist.append(Movie(**mov)) + yield self._movie_watchlist + yield self._movie_watchlist + + @property + @get + def movie_collection(self): + """All :class:`Movie`'s in this :class:`User`'s library collection. + Collection items might include blu-rays, dvds, and digital downloads. + Protected users won't return any data unless you are friends. + """ + if self._movie_collection is None: + ext = 'users/{username}/collection/movies?extended=metadata' + data = yield ext.format(username=slugify(self.username)) + self._movie_collection = [] + for movie in data: + mov = movie.pop('movie') + extract_ids(mov) + self._movie_collection.append(Movie(**mov)) + yield self._movie_collection + + @property + @get + def show_collection(self): + """All :class:`TVShow`'s in this :class:`User`'s library collection. + Collection items might include blu-rays, dvds, and digital downloads. + Protected users won't return any data unless you are friends. + """ + if self._show_collection is None: + ext = 'users/{username}/collection/shows?extended=metadata' + data = yield ext.format(username=slugify(self.username)) + self._show_collection = [] + for show in data: + s = show.pop('show') + extract_ids(s) + sh = TVShow(**s) + sh._seasons = [TVSeason(show=sh.title, **sea) + for sea in show.pop('seasons')] + self._show_collection.append(sh) + yield self._show_collection + + @property + @get + def watched_movies(self): + """Watched profess for all :class:`Movie`'s in this :class:`User`'s + collection. + """ + if self._watched_movies is None: + data = yield 'users/{user}/watched/movies'.format( + user=slugify(self.username) + ) + self._watched_movies = [] + for movie in data: + movie_data = movie.pop('movie') + extract_ids(movie_data) + movie_data.update(movie) + self._watched_movies.append(Movie(**movie_data)) + yield self._watched_movies + + @property + @get + def watched_shows(self): + """Watched profess for all :class:`TVShow`'s in this :class:`User`'s + collection. + """ + if self._watched_shows is None: + data = yield 'users/{user}/watched/shows'.format( + user=slugify(self.username) + ) + self._watched_shows = [] + for show in data: + show_data = show.pop('show') + extract_ids(show_data) + show_data.update(show) + self._watched_shows.append(TVShow(**show_data)) + yield self._watched_shows + + @property + @get + def watching(self): + """The :class:`TVEpisode` or :class:`Movie` this :class:`User` is + currently watching. If they aren't watching anything, a blank object + will be returned. Protected users won't return any data unless you are + friends. + """ + data = yield 'users/{user}/watching'.format( + user=slugify(self.username)) + + # if a user isn't watching anything, trakt returns a 204 + if data is None or data == '': + yield None + + media_type = data.pop('type') + if media_type == 'movie': + movie_data = data.pop('movie') + extract_ids(movie_data) + movie_data.update(data) + yield Movie(**movie_data) + else: # media_type == 'episode' + ep_data = data.pop('episode') + extract_ids(ep_data) + sh_data = data.pop('show') + ep_data.update(data, show=sh_data.get('title')) + yield TVEpisode(**ep_data) + + @staticmethod + def get_follower_requests(): + """Return a list of all pending follower requests for the authenticated + user + """ + return get_all_requests() + + def get_list(self, title): + """Get the specified list from this :class:`User`. Protected + :class:`User`'s won't return any data unless you are friends. To view + your own private lists, you will need to authenticate as yourself. + """ + return UserList.get(title, self.username) + + @get + def get_ratings(self, media_type='movies', rating=None): + """Get a user's ratings filtered by type. You can optionally filter for + a specific rating between 1 and 10. + + :param media_type: The type of media to search for. Must be one of + 'movies', 'shows', 'seasons', 'episodes' + :param rating: Optional rating between 1 and 10 + """ + uri = 'users/{user}/ratings/{type}'.format(user=slugify(self.username), + type=media_type) + if rating is not None: + uri += '/{rating}'.format(rating=rating) + data = yield uri + # TODO (moogar0880) - return as objects + yield data + + @get + def get_stats(self): + """Returns stats about the movies, shows, and episodes a user has + watched and collected + """ + data = yield 'users/{user}/stats'.format(user=slugify(self.username)) + yield data + + def follow(self): + """Follow this :class:`User`""" + follow(self.username) + + def unfollow(self): + """Unfollow this :class:`User`, if you already follow them""" + unfollow(self.username) + + def __str__(self): + """String representation of a :class:`User`""" + return ': {}'.format(unicode_safe(self.username)) + __repr__ = __str__ + + +# get decorator issue workaround - "It's a little hacky" +UserList.get = UserList._get diff --git a/ext/trakt/utils.py b/ext/trakt/utils.py new file mode 100644 index 0000000000..e0a3725f55 --- /dev/null +++ b/ext/trakt/utils.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +import re +import six +import unicodedata +from datetime import datetime + +__author__ = 'Jon Nappi' +__all__ = ['slugify', 'airs_date', 'now', 'timestamp', 'extract_ids', + 'unicode_safe'] + + +def slugify(value): + """Converts to lowercase, removes non-word characters (alphanumerics and + underscores) and converts spaces to hyphens. Also strips leading and + trailing whitespace. + + Adapted from django.utils.text.slugify + """ + if six.PY2 and isinstance(value, str): + value = unicode(value, 'utf-8') # NOQA + nfkd_form = unicodedata.normalize('NFKD', value) + decoded = nfkd_form.encode('ascii', 'ignore').decode('utf-8') + value = re.sub(r'[^\w\s-]', ' ', decoded).strip().lower() + return re.sub(r'[-\s]+', '-', value) + + +def airs_date(airs_at): + """convert a timestamp of the form '2015-02-01T05:30:00.000-08:00Z' to a + python datetime object (with time zone information removed) + """ + if airs_at is None: + return None + parsed = airs_at.split('-')[:-1] + if len(parsed) == 2: + return datetime.strptime(airs_at[:-1], '%Y-%m-%dT%H:%M:%S.000') + return datetime.strptime('-'.join(parsed), '%Y-%m-%dT%H:%M:%S.000') + + +def now(): + """Get the current day in the format expected by each :class:`Calendar`""" + meow = datetime.now() + year = meow.year + month = meow.month if meow.month >= 10 else '0{}'.format(meow.month) + day = meow.day if meow.day >= 10 else '0{}'.format(meow.day) + return '{}-{}-{}'.format(year, month, day) + + +def timestamp(date_object): + """Generate a trakt formatted timestamp from the given date object""" + fmt = '%Y-%m-%d:T%H:%M:%S.000Z' + return date_object.strftime(fmt) + + +def extract_ids(id_dict): + """Extract the inner `ids` dict out of trakt JSON responses and insert them + into the containing `dict`. Then return the input `dict` + """ + id_dict.update(id_dict.pop('ids', {})) + return id_dict + + +def unicode_safe(s): + if six.PY3: + return s + return s.encode('ascii', 'ignore').decode('ascii') diff --git a/medusa/__main__.py b/medusa/__main__.py index cb0812aabc..dd060565cc 100755 --- a/medusa/__main__.py +++ b/medusa/__main__.py @@ -100,6 +100,8 @@ from medusa.tv import Series from medusa.updater.version_checker import CheckVersion +import trakt + logger = logging.getLogger(__name__) @@ -1014,6 +1016,9 @@ def initialize(self, console_logging=True): app.FALLBACK_PLEX_NOTIFICATIONS = check_setting_int(app.CFG, 'General', 'fallback_plex_notifications', 1) app.FALLBACK_PLEX_TIMEOUT = check_setting_int(app.CFG, 'General', 'fallback_plex_timeout', 3) + # Initialize trakt config path. + trakt.core.CONFIG_PATH = os.path.join(app.CACHE_DIR, '.pytrakt.json') + # reconfigure the logger app_logger.reconfigure() diff --git a/medusa/app.py b/medusa/app.py index a2b2c4db32..2a2fc8164b 100644 --- a/medusa/app.py +++ b/medusa/app.py @@ -7,6 +7,7 @@ import sys from threading import Lock + CUSTOMIZABLE_LOGS = [ 'Missed file: {missed_file}', 'Problem(s) during processing, failed for the following files/folders: ', @@ -486,7 +487,7 @@ def __init__(self): self.SLACK_NOTIFY_SUBTITLEDOWNLOAD = None self.SLACK_WEBHOOK = None - self.USE_TRAKT = False + self._USE_TRAKT = False self.TRAKT_USERNAME = None self.TRAKT_ACCESS_TOKEN = None self.TRAKT_REFRESH_TOKEN = None @@ -638,13 +639,12 @@ def __init__(self): self.NO_RESTART = False self.TMDB_API_KEY = 'edc5f123313769de83a71e157758030b' - # TRAKT_API_KEY = 'd4161a7a106424551add171e5470112e4afdaf2438e6ef2fe0548edc75924868' - self.TRAKT_API_KEY = '5c65f55e11d48c35385d9e8670615763a605fad28374c8ae553a7b7a50651ddd' self.TRAKT_API_SECRET = 'b53e32045ac122a445ef163e6d859403301ffe9b17fb8321d428531b69022a82' self.TRAKT_PIN_URL = 'https://trakt.tv/pin/4562' self.TRAKT_OAUTH_URL = 'https://trakt.tv/' self.TRAKT_API_URL = 'https://api.trakt.tv/' + self.TRAKT_DEVICE_CODE = {} self.FANART_API_KEY = '9b3afaf26f6241bdb57d6cc6bd798da7' @@ -720,6 +720,17 @@ def CUSTOM_LOGS(self, logs): new_value = {'level': level} main_db_con.upsert('custom_logs', new_value, control_value) + @property + def USE_TRAKT(self): + """Return USE_TRAKT value.""" + return self._USE_TRAKT + + @USE_TRAKT.setter + def USE_TRAKT(self, value): + """Set USE_TRAKT value and start trakt_checker thread if needed.""" + from medusa import config + config.change_USE_TRAKT(bool(value)) + app = MedusaApp() for app_key, app_value in app.__dict__.items(): diff --git a/medusa/config.py b/medusa/config.py index 47812ddf28..2ecef2f1ef 100644 --- a/medusa/config.py +++ b/medusa/config.py @@ -25,8 +25,7 @@ import re from builtins import object from builtins import str - -from contextlib2 import suppress +from contextlib import suppress from medusa import app, common, db, helpers, logger, naming from medusa.helper.common import try_int @@ -368,7 +367,7 @@ def change_DOWNLOAD_PROPERS(download_propers): log.info(u'Unable to start PROPERFINDER thread. Already running') else: app.proper_finder_scheduler.enable = False - app.trakt_checker_scheduler.silent = True + app.proper_finder_scheduler.silent = True log.info(u'Stopping PROPERFINDER thread') @@ -379,13 +378,14 @@ def change_USE_TRAKT(use_trakt): :param use_trakt: New desired state """ - use_trakt = checkbox_to_value(use_trakt) - - if app.USE_TRAKT == use_trakt: + if app._USE_TRAKT == use_trakt: return - app.USE_TRAKT = use_trakt - if app.USE_TRAKT: + app._USE_TRAKT = use_trakt + if app._USE_TRAKT: + # Trakt checker hasn't been initialized yet. Can't do anything with it right now. + if app.trakt_checker_scheduler is None: + return if not app.trakt_checker_scheduler.enable: log.info(u'Starting TRAKTCHECKER thread') app.trakt_checker_scheduler.silent = False diff --git a/medusa/failed_history.py b/medusa/failed_history.py index c958821f64..deb2e61c0f 100644 --- a/medusa/failed_history.py +++ b/medusa/failed_history.py @@ -160,14 +160,14 @@ def revert_episode(ep_obj): (show=ep_obj.series.name, ep=episode_num(ep_obj.season, ep_obj.episode))) with ep_obj.lock: if ep_obj.episode in history_eps: - ep_obj.status = history_eps[ep_obj.episode]['status'] + ep_obj._status = history_eps[ep_obj.episode]['status'] logger.log(u'Episode have a previous status to revert. Setting it back to {0}'.format (statusStrings[ep_obj.status]), logger.DEBUG) else: logger.log(u'Episode does not have a previous snatched status ' u'to revert. Setting it back to WANTED', logger.DEBUG) - ep_obj.status = WANTED + ep_obj._status = WANTED ep_obj.save_to_db() except EpisodeNotFoundException as error: @@ -187,7 +187,7 @@ def mark_failed(ep_obj): try: with ep_obj.lock: - ep_obj.status = FAILED + ep_obj._status = FAILED ep_obj.save_to_db() except EpisodeNotFoundException as error: diff --git a/medusa/helpers/externals.py b/medusa/helpers/externals.py index e3d34fc83d..9aa32f3308 100644 --- a/medusa/helpers/externals.py +++ b/medusa/helpers/externals.py @@ -16,7 +16,9 @@ from six import viewitems -from traktor import AuthException, TokenExpiredException, TraktApi, TraktException +from trakt import sync +from trakt.errors import TraktException + log = BraceAdapter(logging.getLogger(__name__)) log.logger.addHandler(logging.NullHandler()) @@ -27,27 +29,6 @@ def get_trakt_externals(externals): :param externals: Dictionary of key/value pairs with external id's. """ - def trakt_request(api, trakt_url): - """Perform the request and handle possible token refresh.""" - try: - trakt_result = api.request(trakt_url) or [] - if api.access_token_refreshed: - app.TRAKT_ACCESS_TOKEN = api.access_token - app.TRAKT_REFRESH_TOKEN = api.refresh_token - app.instance.save_config() - except (AuthException, TraktException, TokenExpiredException) as error: - log.info(u'Could not use Trakt to enrich with externals: {0!r}', error) - return [] - else: - return trakt_result - - trakt_settings = {'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - - id_lookup = '/search/{external_key}/{external_value}?type=show' trakt_mapping = {'tvdb_id': 'tvdb', 'imdb_id': 'imdb', 'tmdb_id': 'tmdb', 'trakt_id': 'trakt'} trakt_mapping_rev = {v: k for k, v in viewitems(trakt_mapping)} @@ -55,16 +36,23 @@ def trakt_request(api, trakt_url): if not trakt_mapping.get(external_key) or not externals[external_key]: continue - url = id_lookup.format(external_key=trakt_mapping[external_key], external_value=externals[external_key]) log.debug( u'Looking for externals using Trakt and {indexer} id {number}', { 'indexer': trakt_mapping[external_key], 'number': externals[external_key], } ) - result = trakt_request(trakt_api, url) - if result and len(result) and result[0].get('show') and result[0]['show'].get('ids'): - ids = {trakt_mapping_rev[k]: v for k, v in viewitems(result[0]['show'].get('ids')) + + try: + result = sync.search_by_id(externals[external_key], id_type=trakt_mapping[external_key], media_type='show') + except TraktException as error: + log.warning('Error getting external key {external}, error: {error!r}', { + 'external': trakt_mapping[external_key], 'error': error + }) + return {} + + if result and len(result) and result[0].ids.get('ids'): + ids = {trakt_mapping_rev[k]: v for k, v in result[0].ids.get('ids').items() if v and trakt_mapping_rev.get(k)} return ids return {} diff --git a/medusa/helpers/trakt.py b/medusa/helpers/trakt.py new file mode 100644 index 0000000000..b6da7d9541 --- /dev/null +++ b/medusa/helpers/trakt.py @@ -0,0 +1,95 @@ +"""Module with Trakt helper methods.""" + + +import logging + +from medusa.helpers import get_title_without_year +from medusa.logger.adapters.style import BraceAdapter + +from trakt import calendar, tv, users +from trakt.errors import TraktException + + +log = BraceAdapter(logging.getLogger(__name__)) +log.logger.addHandler(logging.NullHandler()) + + +def get_trakt_user(): + """Get PyTrakt user object.""" + try: + user = users.get_user_settings() + username = user['user']['username'] + return users.User(username) + except TraktException as error: + log.warning('Unable to get trakt user, error: {error}', {'error': error}) + raise + + +def get_trakt_show_collection(trakt_list, limit=None): + """ + Flesh out the different list_types into pyTrakt method calls. + + Call the relevant method, with paramaters if required. + Return Array of TvShows. + :param trakt_list: String description of the trakt list to return. + :returns: Array of PyTrakt TvShow objects. + """ + try: + if trakt_list == 'trending': + return tv.trending_shows(limit=limit, extended='full,images') + elif trakt_list == 'popular': + return tv.popular_shows(limit=limit, extended='full,images') + elif trakt_list == 'anticipated': + return tv.anticipated_shows(limit=limit, extended='full,images') + elif trakt_list == 'collected': + return tv.collected_shows(limit=limit, extended='full,images') + elif trakt_list == 'watched': + return tv.watched_shows(limit=limit, extended='full,images') + elif trakt_list == 'played': + return tv.played_shows(limit=limit, extended='full,images') + elif trakt_list == 'recommended': + return tv.recommended_shows(extended='full,images') + elif trakt_list == 'newshow': + return calendar.PremiereCalendar(days=30, extended='full,images', returns='shows') + elif trakt_list == 'newseason': + return calendar.SeasonCalendar(days=30, extended='full,images', returns='shows') + + return tv.anticipated_shows(limit=limit, extended='full,images') + except TraktException as error: + log.warning('Unable to get trakt list {trakt_list}: {error!r}', {'trakt_list': trakt_list, 'error': error}) + + +def create_show_structure(show_obj): + """Prepare a trakt standard media object. With the show identifier.""" + show = { + 'title': get_title_without_year(show_obj.name, show_obj.start_year), + 'year': show_obj.start_year, + 'ids': {} + } + for valid_trakt_id in ['tvdb_id', 'trakt_id', 'tmdb_id', 'imdb_id']: + if show_obj.externals.get(valid_trakt_id): + show['ids'][valid_trakt_id[:-3]] = show_obj.externals.get(valid_trakt_id) + return show + + +def create_episode_structure(show_obj, episodes): + """Prepare a trakt standard media object. With the show and episode identifiers.""" + if not isinstance(episodes, list): + episodes = [episodes] + + show = create_show_structure(show_obj) + + # Add episodes to the media_object. + show['seasons'] = [] + + for ep_obj in episodes: + if ep_obj.season not in show['seasons']: + show['seasons'].append({ + 'number': ep_obj.season, + 'episodes': [] + }) + + season = [s for s in show['seasons'] if s['number'] == ep_obj.season][0] + season['episodes'].append({'number': ep_obj.episode}) + + return show diff --git a/medusa/naming.py b/medusa/naming.py index eb3505ce73..8ba4ac7023 100644 --- a/medusa/naming.py +++ b/medusa/naming.py @@ -186,7 +186,7 @@ def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): # make a fake episode object ep = Episode(series=series, season=2, episode=3) - ep.status = DOWNLOADED + ep._status = DOWNLOADED ep.quality = Quality.HDTV ep.airdate = datetime.date(2011, 3, 9) ep.name = 'Ep Name' @@ -211,14 +211,14 @@ def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): second_ep = Episode(series, 2, 4) second_ep.name = 'Ep Name (2)' - second_ep.status = DOWNLOADED + second_ep._status = DOWNLOADED second_ep.quality = Quality.HDTV second_ep.absolute_number = 14 second_ep.release_name = ep.release_name third_ep = Episode(series, 2, 5) third_ep.name = 'Ep Name (3)' - third_ep.status = DOWNLOADED + third_ep._status = DOWNLOADED third_ep.quality = Quality.HDTV third_ep.absolute_number = 15 third_ep.release_name = ep.release_name diff --git a/medusa/notifiers/trakt.py b/medusa/notifiers/trakt.py index ced74b97b2..2126de8c4a 100644 --- a/medusa/notifiers/trakt.py +++ b/medusa/notifiers/trakt.py @@ -8,10 +8,13 @@ from medusa import app from medusa.helpers import get_title_without_year +from medusa.helpers.trakt import create_episode_structure, create_show_structure, get_trakt_user from medusa.indexers.utils import get_trakt_indexer from medusa.logger.adapters.style import BraceAdapter -from traktor import AuthException, TokenExpiredException, TraktApi, TraktException +from trakt import sync, tv +from trakt.errors import TraktException + log = BraceAdapter(logging.getLogger(__name__)) log.logger.addHandler(logging.NullHandler()) @@ -50,14 +53,6 @@ def update_library(ep_obj): if not get_trakt_indexer(ep_obj.series.indexer): return - # Create a trakt settings dict - trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - - trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - if app.USE_TRAKT: try: # URL parameters @@ -74,150 +69,83 @@ def update_library(ep_obj): data['shows'][0]['ids'][get_trakt_indexer(ep_obj.series.indexer)] = ep_obj.series.indexerid - if app.TRAKT_SYNC_WATCHLIST: - if app.TRAKT_REMOVE_SERIESLIST: - trakt_api.request('sync/watchlist/remove', data, method='POST') - # Add Season and Episode + Related Episodes data['shows'][0]['seasons'] = [{'number': ep_obj.season, 'episodes': []}] - for relEp_Obj in [ep_obj] + ep_obj.related_episodes: - data['shows'][0]['seasons'][0]['episodes'].append({'number': relEp_Obj.episode}) + for rel_ep_obj in [ep_obj] + ep_obj.related_episodes: + data['shows'][0]['seasons'][0]['episodes'].append({'number': rel_ep_obj.episode}) if app.TRAKT_SYNC_WATCHLIST: - if app.TRAKT_REMOVE_WATCHLIST: - trakt_api.request('sync/watchlist/remove', data, method='POST') + if app.TRAKT_REMOVE_SERIESLIST: + sync.remove_from_watchlist(data) # update library - trakt_api.request('sync/collection', data, method='POST') - - except (TokenExpiredException, TraktException, AuthException) as error: - log.debug('Unable to update Trakt: {0!r}', error) + sync.add_to_collection(data) + except TraktException as error: + log.warning('Unable to update Trakt: {error!r}', {'error': error}) @staticmethod - def update_watchlist(show_obj=None, s=None, e=None, data_show=None, data_episode=None, update='add'): - """Send a request to trakt indicating that the given episode is part of our library. - - show_obj: The Series object to add to trakt - s: season number - e: episode number - data_show: structured object of shows trakt type - data_episode: structured object of episodes trakt type - update: type o action add or remove - """ - # Check if TRAKT supports that indexer - if not get_trakt_indexer(show_obj.indexer): - return - - trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - - trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - - if app.USE_TRAKT: + def update_watchlist_show(show_obj, remove=False): + """Use Trakt sync/watchlist to updata a show.""" + trakt_media_object = {'shows': [create_show_structure(show_obj)]} - data = {} - try: - # URL parameters - if show_obj is not None: - title = get_title_without_year(show_obj.name, show_obj.start_year) - data = { - 'shows': [ - { - 'title': title, - 'year': show_obj.start_year, - 'ids': {}, - } - ] - } - data['shows'][0]['ids'][get_trakt_indexer(show_obj.indexer)] = show_obj.indexerid - elif data_show is not None: - data.update(data_show) - else: - log.warning( - "There's a coding problem contact developer. It's needed to be provided at" - ' least one of the two: data_show or show_obj', - ) - return False - - if data_episode is not None: - data['shows'][0].update(data_episode) - - elif s is not None: - # trakt URL parameters - season = { - 'season': [ - { - 'number': s, - } - ] - } - - if e is not None: - # trakt URL parameters - episode = { - 'episodes': [ - { - 'number': e - } - ] - } + try: + if remove: + result = sync.remove_from_watchlist(trakt_media_object) + else: + result = sync.add_to_watchlist(trakt_media_object) + except TraktException as error: + log.warning('Unable to update Trakt: {error!r}', {'error': error}) + return False - season['season'][0].update(episode) + if result and (result.get('added') or result.get('existing')): + if result['added']['shows']: + return True - data['shows'][0].update(season) + return False - trakt_url = 'sync/watchlist' - if update == 'remove': - trakt_url += '/remove' + @staticmethod + def update_watchlist_episode(episodes, remove=False): + """ + Use Trakt sync/watchlist to updata an episode. - trakt_api.request(trakt_url, data, method='POST') + As we want to prevent Trakt.tv api rate limiting. Try to use the array of episodes + as much as possible. + :param episodes: An episode object or array of episode objects. + """ + try: + if remove: + result = sync.remove_from_watchlist({'shows': [create_episode_structure(episodes)]}) + else: + result = sync.add_to_watchlist({'shows': [create_episode_structure(episodes)]}) + except TraktException as error: + log.warning('Unable to update Trakt watchlist: {error!r}', {'error': error}) + return False - except (TokenExpiredException, TraktException, AuthException) as error: - log.debug('Unable to update Trakt watchlist: {0!r}', error) - return False + if result and (result.get('added') or result.get('existing')): + if result['added']['episodes']: + return True - return True + return False @staticmethod - def trakt_show_data_generate(data): - """Build the JSON structure to send back to Trakt.""" - show_list = [] - for indexer, indexerid, title, year in data: - show = {'title': title, 'year': year, 'ids': {}} - show['ids'][get_trakt_indexer(indexer)] = indexerid - show_list.append(show) - - post_data = {'shows': show_list} + def add_episode_to_watchlist(episode): + """ + Add an episode to the trakt watchlist. - return post_data + :params episode: Episode Object. + """ + show_id = None - @staticmethod - def trakt_episode_data_generate(data): - """Build the JSON structure to send back to Trakt.""" - # Find how many unique season we have - unique_seasons = [] - for season, episode in data: - if season not in unique_seasons: - unique_seasons.append(season) - - # build the query - seasons_list = [] - for searchedSeason in unique_seasons: - episodes_list = [] - for season, episode in data: - if season == searchedSeason: - episodes_list.append({'number': episode}) - seasons_list.append({'number': searchedSeason, 'episodes': episodes_list}) - - post_data = {'seasons': seasons_list} - - return post_data + try: + tv_show = tv.TVShow(show_id) + tv_episode = tv.TVEpisode(tv_show, episode.season, episode.episode) + tv_episode.add_to_watchlist() + except TraktException as error: + log.warning('Unable to add episode to watchlist: {error!r}', {'error': error}) @staticmethod - def test_notify(username, blacklist_name=None): + def test_notify(blacklist_name=None): """Send a test notification to trakt with the given authentication info and returns a boolean. api: The api string to use @@ -226,23 +154,18 @@ def test_notify(username, blacklist_name=None): Returns: True if the request succeeded, False otherwise """ try: - trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - - trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - trakt_api.validate_account() + trakt_user = get_trakt_user() if blacklist_name and blacklist_name is not None: - trakt_lists = trakt_api.request('users/' + username + '/lists') + trakt_lists = trakt_user.lists + found = False for trakt_list in trakt_lists: - if trakt_list['ids']['slug'] == blacklist_name: + if trakt_list.slug == blacklist_name: return 'Test notice sent successfully to Trakt' if not found: return "Trakt blacklist doesn't exists" else: return 'Test notice sent successfully to Trakt' - except (TokenExpiredException, TraktException, AuthException) as error: - log.warning('Unable to test TRAKT: {0!r}', error) + except TraktException as error: + log.warning('Unable to test TRAKT: {error!r}', {'error': error}) return 'Test notice failed to Trakt: {0!r}'.format(error) diff --git a/medusa/post_processor.py b/medusa/post_processor.py index 65be44e86e..9f0d460a3c 100644 --- a/medusa/post_processor.py +++ b/medusa/post_processor.py @@ -1181,7 +1181,7 @@ def process(self): else: cur_ep.release_name = u'' - cur_ep.status = DOWNLOADED + cur_ep._status = DOWNLOADED cur_ep.quality = new_ep_quality cur_ep.subtitles = u'' diff --git a/medusa/queues/show_queue.py b/medusa/queues/show_queue.py index d83ca92657..481f57ce8b 100644 --- a/medusa/queues/show_queue.py +++ b/medusa/queues/show_queue.py @@ -56,7 +56,8 @@ from six import ensure_text, text_type, viewitems -from traktor import TraktException +from trakt.errors import TraktException + log = BraceAdapter(logging.getLogger(__name__)) log.logger.addHandler(logging.NullHandler()) @@ -945,6 +946,9 @@ def run(self): ' Error: {error_msg}', {'id': self.show.series_id, 'show': self.show.name, 'error_msg': error} ) + except Exception as error: + log.exception('Exception occurred while trying to delete show {show}, error: {error', + {'show': self.show.name, 'error': error}) self.show.delete_show(full=self.full) diff --git a/medusa/schedulers/episode_updater.py b/medusa/schedulers/episode_updater.py index dd300653af..0821cb9325 100644 --- a/medusa/schedulers/episode_updater.py +++ b/medusa/schedulers/episode_updater.py @@ -112,7 +112,7 @@ def run(self, force=False): continue with cur_ep.lock: - cur_ep.status = series_obj.default_ep_status if cur_ep.season else common.SKIPPED + cur_ep._status = series_obj.default_ep_status if cur_ep.season else common.SKIPPED log.info( 'Setting status ({status}) for show airing today: {name} {special}', { 'name': cur_ep.pretty_name(), diff --git a/medusa/schedulers/trakt_checker.py b/medusa/schedulers/trakt_checker.py index 70621f1326..439412d5f1 100644 --- a/medusa/schedulers/trakt_checker.py +++ b/medusa/schedulers/trakt_checker.py @@ -12,14 +12,16 @@ from medusa import app, db, ui from medusa.common import ARCHIVED, DOWNLOADED, Quality, SKIPPED, SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, WANTED from medusa.helper.common import episode_num -from medusa.helpers import get_title_without_year +from medusa.helpers.trakt import create_episode_structure, create_show_structure, get_trakt_user from medusa.indexers.config import EXTERNAL_IMDB, EXTERNAL_TRAKT, indexerConfig from medusa.indexers.utils import get_trakt_indexer from medusa.logger.adapters.style import BraceAdapter from medusa.search.queue import BacklogQueueItem from medusa.show.show import Show -from traktor import AuthException, TokenExpiredException, TraktApi, TraktException +from trakt import sync, tv +from trakt.errors import TraktException + log = BraceAdapter(logging.getLogger(__name__)) log.logger.addHandler(logging.NullHandler()) @@ -43,7 +45,7 @@ def set_episode_to_wanted(show, season, episode): }) # figure out what segment the episode is in and remember it so we can backlog it - ep_obj.status = WANTED + ep_obj._status = WANTED # As we created the episode and updated the status, need to save to DB ep_obj.save_to_db() @@ -61,12 +63,7 @@ class TraktChecker(object): def __init__(self): """Initialize the class.""" - trakt_settings = {'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - self.trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - self.todoWanted = [] + self.todo_wanted = [] self.show_watchlist = {} self.episode_watchlist = {} self.collection_list = {} @@ -78,7 +75,7 @@ def run(self, force=False): # add shows from Trakt watchlist if app.TRAKT_SYNC_WATCHLIST: - self.todoWanted = [] # its about to all get re-added + self.todo_wanted = [] # its about to all get re-added if len(app.ROOT_DIRS) < 2: log.warning('No default root directory') ui.notifications.error('Unable to add show', @@ -86,42 +83,27 @@ def run(self, force=False): 'Please configure in general settings!') return - self.sync_watchlist() - self.sync_library() + try: + self.sync_watchlist() + self.sync_library() + except TraktException as error: + log.exception('Trakt exception while running trakt_checker.\nError: {error}', {'error': error}) self.amActive = False - def _request(self, path, data=None, method='GET'): - """Fetch shows from trakt and store the refresh token when needed.""" - try: - library_shows = self.trakt_api.request(path, data, method=method) or [] - if self.trakt_api.access_token_refreshed: - app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token - app.TRAKT_REFRESH_TOKEN = self.trakt_api.refresh_token - app.instance.save_config() - except TokenExpiredException: - log.warning(u'You need to get a PIN and authorize Medusa app') - app.TRAKT_ACCESS_TOKEN = '' - app.TRAKT_REFRESH_TOKEN = '' - app.instance.save_config() - raise TokenExpiredException('You need to get a PIN and authorize Medusa app') - - return library_shows - def find_show(self, indexerid, indexer): """Find show in Trakt library.""" trakt_library = [] try: - trakt_library = self._request('sync/collection/shows') - except (TraktException, AuthException, TokenExpiredException) as error: + trakt_library = sync.get_collection('shows') + except TraktException as error: log.info('Unable to retrieve shows from Trakt collection. Error: {error!r}', {'error': error}) if not trakt_library: log.info('No shows found in your Trakt library. Nothing to sync') return - trakt_show = [x for x in trakt_library if - get_trakt_indexer(indexer) and - int(indexerid) in [int(x['show']['ids'].get(get_trakt_indexer(indexer)))]] + trakt_show = [show for show in trakt_library if + get_trakt_indexer(indexer) and int(indexerid) in [int(show.ids['ids'].get(get_trakt_indexer(indexer)))]] return trakt_show if trakt_show else None @@ -133,34 +115,20 @@ def remove_show_trakt_library(self, show_obj): if not get_trakt_indexer(show_obj.indexer): return - # URL parameters - title = get_title_without_year(show_obj.name, show_obj.start_year) - data = { - 'shows': [ - { - 'title': title, - 'year': show_obj.start_year, - 'ids': {} - } - ] - } - - data['shows'][0]['ids'][get_trakt_indexer(show_obj.indexer)] = show_obj.indexerid - log.info("Removing '{show}' from Trakt library", {'show': show_obj.name}) # Remove all episodes from the Trakt collection for this show try: self.remove_episode_trakt_collection(filter_show=show_obj) - except (TraktException, AuthException, TokenExpiredException) as error: + except TraktException as error: log.info("Unable to remove all episodes from show '{show}' from Trakt library. Error: {error!r}", { 'show': show_obj.name, 'error': error }) try: - self._request('sync/collection/remove', data, method='POST') - except (TraktException, AuthException, TokenExpiredException) as error: + sync.remove_from_collection(create_show_structure(show_obj)) + except TraktException as error: log.info("Unable to remove show '{show}' from Trakt library. Error: {error!r}", { 'show': show_obj.name, 'error': error @@ -168,39 +136,29 @@ def remove_show_trakt_library(self, show_obj): def add_show_trakt_library(self, show_obj): """Add show to trakt library.""" - data = {} + if self.find_show(show_obj.indexerid, show_obj.indexer): + return - if not self.find_show(show_obj.indexerid, show_obj.indexer): + # Check if TRAKT supports that indexer + if not get_trakt_indexer(show_obj.indexer): + return - # Check if TRAKT supports that indexer - if not get_trakt_indexer(show_obj.indexer): - return + log.info("Adding show '{show}' to Trakt library", {'show': show_obj.name}) - # URL parameters - title = get_title_without_year(show_obj.name, show_obj.start_year) - data = { - 'shows': [ - { - 'title': title, - 'year': show_obj.start_year, - 'ids': {} - } - ] - } + try: + result = sync.add_to_collection(create_show_structure(show_obj)) + except TraktException as error: + log.info("Unable to add show '{show}' to Trakt library. Error: {error!r}", { + 'show': show_obj.name, + 'error': error + }) + return - data['shows'][0]['ids'][get_trakt_indexer(show_obj.indexer)] = show_obj.indexerid + if result and (result.get('added') or result.get('existing')): + if result['added']['shows']: + return True - if data: - log.info("Adding show '{show}' to Trakt library", {'show': show_obj.name}) - - try: - self._request('sync/collection', data, method='POST') - except (TraktException, AuthException, TokenExpiredException) as error: - log.info("Unable to add show '{show}' to Trakt library. Error: {error!r}", { - 'show': show_obj.name, - 'error': error - }) - return + return False def sync_library(self): """Sync Trakt library.""" @@ -219,96 +177,126 @@ def remove_episode_trakt_collection(self, filter_show=None): For episodes that no longer have a media file (location) :param filter_show: optional. Only remove episodes from trakt collection for given shows """ - if app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT: - - params = [] - main_db_con = db.DBConnection() - statuses = [DOWNLOADED, ARCHIVED] - sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name,' \ - 'e.season, e.episode, e.status ' \ - 'FROM tv_episodes AS e, tv_shows AS s WHERE e.indexer = s.indexer AND ' \ - 's.indexer_id = e.showid and e.location = "" ' \ - 'AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) - if filter_show: - sql_selection += ' AND s.indexer_id = ? AND e.indexer = ?' - params = [filter_show.series_id, filter_show.indexer] - - sql_result = main_db_con.select(sql_selection, statuses + params) - - if sql_result: - trakt_data = [] - - for cur_episode in sql_result: - # Check if TRAKT supports that indexer - if not get_trakt_indexer(cur_episode['indexer']): - continue - if self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['indexer_id'], - season=cur_episode['season'], episode=cur_episode['episode'], - list_type='Collection'): - log.info("Removing episode '{show}' {ep} from Trakt collection", { - 'show': cur_episode['show_name'], - 'ep': episode_num(cur_episode['season'], - cur_episode['episode']) - }) - title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear']) - trakt_data.append((cur_episode['indexer_id'], cur_episode['indexer'], - title, cur_episode['startyear'], - cur_episode['season'], cur_episode['episode'])) - - if trakt_data: - try: - data = self.trakt_bulk_data_generate(trakt_data) - self._request('sync/collection/remove', data, method='POST') - self._get_show_collection() - except (TraktException, AuthException, TokenExpiredException) as error: - log.info('Unable to remove episodes from Trakt collection. Error: {error!r}', { - 'error': error - }) + if not (app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT): + return + + params = [] + main_db_con = db.DBConnection() + statuses = [DOWNLOADED, ARCHIVED] + sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name,' \ + 'e.season, e.episode, e.status ' \ + 'FROM tv_episodes AS e, tv_shows AS s WHERE e.indexer = s.indexer AND ' \ + 's.indexer_id = e.showid and e.location = "" ' \ + 'AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) + if filter_show: + sql_selection += ' AND s.indexer_id = ? AND e.indexer = ?' + params = [filter_show.series_id, filter_show.indexer] + + sql_result = main_db_con.select(sql_selection, statuses + params) + + if not sql_result: + return + + episodes = [] + shows = {} + for cur_episode in sql_result: + # Check if TRAKT supports that indexer + if not get_trakt_indexer(cur_episode['indexer']): + continue + + show_id = cur_episode['indexer'], cur_episode['indexer_id'] + episode = cur_episode['season'], cur_episode['episode'] + + if show_id not in shows: + shows[show_id] = [] + + shows[show_id].append(episode) + + media_object_shows = [] + for show_id in shows: + episodes = [] + show_obj = Show.find_by_id(app.showList, show_id[0], show_id[1]) + for season, episode in shows[show_id]: + if not self._check_list( + indexer=show_obj.indexer, indexer_id=show_obj.series_id, + season=season, episode=episode, + list_type='Collection' + ): + continue + + log.info("Removing episode '{show}' {ep} from Trakt collection", { + 'show': show_obj.name, + 'ep': episode_num(season, episode) + }) + episodes.append(show_obj.get_episode(season, episode)) + media_object_shows.append(create_episode_structure(show_obj, episodes)) + + try: + sync.remove_from_collection({'shows': media_object_shows}) + self._get_show_collection() + except TraktException as error: + log.info('Unable to remove episodes from Trakt collection. Error: {error!r}', { + 'error': error + }) def add_episode_trakt_collection(self): """Add all existing episodes to Trakt collections. For episodes that have a media file (location) """ - if app.TRAKT_SYNC and app.USE_TRAKT: + if not(app.TRAKT_SYNC and app.USE_TRAKT): + return - main_db_con = db.DBConnection() - statuses = [DOWNLOADED, ARCHIVED] - sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \ - 'FROM tv_episodes AS e, tv_shows AS s ' \ - 'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid ' \ - "AND e.status in ({0}) AND e.location <> ''".format(','.join(['?'] * len(statuses))) - - sql_result = main_db_con.select(sql_selection, statuses) - - if sql_result: - trakt_data = [] - - for cur_episode in sql_result: - # Check if TRAKT supports that indexer - if not get_trakt_indexer(cur_episode['indexer']): - continue - - if not self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['indexer_id'], - season=cur_episode['season'], episode=cur_episode['episode'], - list_type='Collection'): - log.info("Adding episode '{show}' {ep} to Trakt collection", { - 'show': cur_episode['show_name'], - 'ep': episode_num(cur_episode['season'], - cur_episode['episode']) - }) - title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear']) - trakt_data.append((cur_episode['indexer_id'], cur_episode['indexer'], - title, cur_episode['startyear'], - cur_episode['season'], cur_episode['episode'])) - - if trakt_data: - try: - data = self.trakt_bulk_data_generate(trakt_data) - self._request('sync/collection', data, method='POST') - self._get_show_collection() - except (TraktException, AuthException, TokenExpiredException) as error: - log.info('Unable to add episodes to Trakt collection. Error: {error!r}', {'error': error}) + main_db_con = db.DBConnection() + statuses = [DOWNLOADED, ARCHIVED] + sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \ + 'FROM tv_episodes AS e, tv_shows AS s ' \ + 'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid ' \ + "AND e.status in ({0}) AND e.location <> ''".format(','.join(['?'] * len(statuses))) + + sql_result = main_db_con.select(sql_selection, statuses) + if not sql_result: + return + + episodes = [] + shows = {} + for cur_episode in sql_result: + # Check if TRAKT supports that indexer + if not get_trakt_indexer(cur_episode['indexer']): + continue + + show_id = cur_episode['indexer'], cur_episode['indexer_id'] + episode = cur_episode['season'], cur_episode['episode'] + + if show_id not in shows: + shows[show_id] = [] + + shows[show_id].append(episode) + + media_object_shows = [] + for show_id in shows: + episodes = [] + show_obj = Show.find_by_id(app.showList, show_id[0], show_id[1]) + for season, episode in shows[show_id]: + if not self._check_list( + indexer=show_obj.indexer, indexer_id=show_obj.series_id, + season=season, episode=episode, + list_type='Collection' + ): + continue + + log.info("Adding episode '{show}' {ep} to Trakt collection", { + 'show': show_obj.name, + 'ep': episode_num(season, episode) + }) + episodes.append(show_obj.get_episode(season, episode)) + media_object_shows.append(create_episode_structure(show_obj, episodes)) + + try: + sync.add_to_collection({'shows': media_object_shows}) + self._get_show_collection() + except TraktException as error: + log.info('Unable to add episodes to Trakt collection. Error: {error!r}', {'error': error}) def sync_watchlist(self): """Sync Trakt watchlist.""" @@ -332,197 +320,235 @@ def sync_watchlist(self): def remove_episode_watchlist(self): """Remove episode from Trakt watchlist.""" - if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT: + if not (app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT): + return - main_db_con = db.DBConnection() - statuses = [DOWNLOADED, ARCHIVED] - sql_selection = 'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \ - 'FROM tv_episodes AS e, tv_shows AS s ' \ - 'WHERE e.indexer = s.indexer ' \ - 'AND s.indexer_id = e.showid AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) + main_db_con = db.DBConnection() + statuses = [DOWNLOADED, ARCHIVED] + sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \ + 'FROM tv_episodes AS e, tv_shows AS s ' \ + 'WHERE e.indexer = s.indexer ' \ + 'AND s.indexer_id = e.showid AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) - sql_result = main_db_con.select(sql_selection, statuses) + sql_result = main_db_con.select(sql_selection, statuses) - if sql_result: - trakt_data = [] + if not sql_result: + return - for cur_episode in sql_result: + episodes = [] + shows = {} + for cur_episode in sql_result: + # Check if TRAKT supports that indexer + if not get_trakt_indexer(cur_episode['indexer']): + continue + + show_id = cur_episode['indexer'], cur_episode['indexer_id'] + episode = cur_episode['season'], cur_episode['episode'] + + if show_id not in shows: + shows[show_id] = [] + + shows[show_id].append(episode) + + media_object_shows = [] + for show_id in shows: + episodes = [] + show_obj = Show.find_by_id(app.showList, show_id[0], show_id[1]) + for season, episode in shows[show_id]: + if not self._check_list( + indexer=show_obj.indexer, indexer_id=show_obj.series_id, + season=season, episode=episode, + list_type='Collection' + ): + continue - # Check if TRAKT supports that indexer - if not get_trakt_indexer(cur_episode['indexer']): - continue + log.info("Removing episode '{show}' {ep} from Trakt watchlist", { + 'show': show_obj.name, + 'ep': episode_num(season, episode) + }) + episodes.append(show_obj.get_episode(season, episode)) + media_object_shows.append(create_episode_structure(show_obj, episodes)) - if self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['showid'], - season=cur_episode['season'], episode=cur_episode['episode']): - log.info("Removing episode '{show}' {ep} from Trakt watchlist", { - 'show': cur_episode['show_name'], - 'ep': episode_num(cur_episode['season'], - cur_episode['episode']) - }) - title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear']) - trakt_data.append((cur_episode['showid'], cur_episode['indexer'], - title, cur_episode['startyear'], - cur_episode['season'], cur_episode['episode'])) - - if trakt_data: - try: - data = self.trakt_bulk_data_generate(trakt_data) - self._request('sync/watchlist/remove', data, method='POST') - self._get_episode_watchlist() - except (TraktException, AuthException, TokenExpiredException) as error: - log.info('Unable to remove episodes from Trakt watchlist. Error: {error!r}', { - 'error': error - }) + try: + sync.remove_from_collection({'shows': media_object_shows}) + self._get_episode_watchlist() + except TraktException as error: + log.info('Unable to remove episodes from Trakt watchlist. Error: {error!r}', { + 'error': error + }) def add_episode_watchlist(self): """Add episode to Tratk watchlist.""" - if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT: + if not(app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT): + return - main_db_con = db.DBConnection() - statuses = [SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, WANTED] - sql_selection = 'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \ - 'FROM tv_episodes AS e, tv_shows AS s ' \ - 'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid AND s.paused = 0 ' \ - 'AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) - - sql_result = main_db_con.select(sql_selection, statuses) - - if sql_result: - trakt_data = [] - - for cur_episode in sql_result: - # Check if TRAKT supports that indexer - if not get_trakt_indexer(cur_episode['indexer']): - continue - - if not self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['showid'], - season=cur_episode['season'], episode=cur_episode['episode']): - log.info("Adding episode '{show}' {ep} to Trakt watchlist", { - 'show': cur_episode['show_name'], - 'ep': episode_num(cur_episode['season'], - cur_episode['episode']) - }) - title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear']) - trakt_data.append((cur_episode['showid'], cur_episode['indexer'], title, - cur_episode['startyear'], cur_episode['season'], cur_episode['episode'])) - - if trakt_data: - try: - data = self.trakt_bulk_data_generate(trakt_data) - self._request('sync/watchlist', data, method='POST') - self._get_episode_watchlist() - except (TraktException, AuthException, TokenExpiredException) as error: - log.info('Unable to add episode to Trakt watchlist. Error: {error!r}', { - 'error': error - }) + main_db_con = db.DBConnection() + statuses = [SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, WANTED] + sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \ + 'FROM tv_episodes AS e, tv_shows AS s ' \ + 'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid AND s.paused = 0 ' \ + 'AND e.status in ({0})'.format(','.join(['?'] * len(statuses))) + + sql_result = main_db_con.select(sql_selection, statuses) + + if not sql_result: + return + + episodes = [] + shows = {} + for cur_episode in sql_result: + # Check if TRAKT supports that indexer + if not get_trakt_indexer(cur_episode['indexer']): + continue + + show_id = cur_episode['indexer'], cur_episode['indexer_id'] + episode = cur_episode['season'], cur_episode['episode'] + + if show_id not in shows: + shows[show_id] = [] + + shows[show_id].append(episode) + + media_object_shows = [] + for show_id in shows: + episodes = [] + show_obj = Show.find_by_id(app.showList, show_id[0], show_id[1]) + for season, episode in shows[show_id]: + if not self._check_list( + indexer=show_obj.indexer, indexer_id=show_obj.series_id, + season=season, episode=episode, + list_type='Collection' + ): + continue + + log.info("Adding episode '{show}' {ep} to Trakt watchlist", { + 'show': show_obj.name, + 'ep': episode_num(season, episode) + }) + episodes.append(show_obj.get_episode(season, episode)) + media_object_shows.append(create_episode_structure(show_obj, episodes)) + + try: + sync.add_to_watchlist({'shows': media_object_shows}) + self._get_episode_watchlist() + except TraktException as error: + log.info('Unable to add episode to Trakt watchlist. Error: {error!r}', { + 'error': error + }) def add_show_watchlist(self): """Add show to Trakt watchlist. It will add all shows from Medusa library """ - if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT: - if app.showList: - trakt_data = [] - - for show_obj in app.showList: - if not self._check_list(show_obj=show_obj, list_type='Show'): - log.info("Adding show '{show}' to Trakt watchlist", {'show': show_obj.name}) - title = get_title_without_year(show_obj.name, show_obj.start_year) - show_el = {'title': title, 'year': show_obj.start_year, 'ids': {}} - trakt_data.append(show_el) - - if trakt_data: - try: - data = {'shows': trakt_data} - self._request('sync/watchlist', data, method='POST') - except (TraktException, AuthException, TokenExpiredException) as error: - log.info('Unable to add shows to Trakt watchlist. Error: {error!r}', {'error': error}) - self._get_show_watchlist() + if not (app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT): + return + + if not app.showList: + return + + trakt_show_objects = [] + for show_obj in app.showList: + if not self._check_list(show_obj=show_obj, list_type='Show'): + log.info("Adding show '{show}' to Trakt watchlist", {'show': show_obj.name}) + trakt_show_objects.append(create_show_structure(show_obj)) + + if trakt_show_objects: + try: + sync.add_to_watchlist({'shows': trakt_show_objects}) + except TraktException as error: + log.info('Unable to add shows to Trakt watchlist. Error: {error!r}', {'error': error}) + self._get_show_watchlist() def remove_from_library(self): - """Remove show from Medusa library is if ended/completed.""" - if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT and app.TRAKT_REMOVE_SHOW_FROM_APPLICATION: - log.debug('Retrieving ended/completed shows to remove from Medusa') - - if app.showList: - for show in app.showList: - if show.status == 'Ended': - trakt_id = show.externals.get('trakt_id', None) - if not (trakt_id or show.imdb_id): - log.info("Unable to check Trakt progress for show '{show}' " - 'because Trakt|IMDB ID is missing. Skipping', {'show': show.name}) - continue - - try: - progress = self._request('shows/{0}/progress/watched'.format(trakt_id or show.imdb_id)) - except (TraktException, AuthException, TokenExpiredException) as error: - log.info("Unable to check if show '{show}' is ended/completed. Error: {error!r}", { - 'show': show.name, - 'error': error - }) - continue - else: - if progress.get('aired', True) == progress.get('completed', False): - app.show_queue_scheduler.action.removeShow(show, full=True) - log.info("Show '{show}' has being queued to be removed from Medusa library", { - 'show': show.name - }) + """Remove show from Medusa library if it is ended/completed.""" + if not (app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT and app.TRAKT_REMOVE_SHOW_FROM_APPLICATION): + return + + log.debug('Retrieving ended/completed shows to remove from Medusa') + + if not app.showList: + return + + for show in app.showList: + if show.status == 'Ended': + trakt_id = show.externals.get('trakt_id', None) + if not (trakt_id or show.imdb_id): + log.info("Unable to check Trakt progress for show '{show}' " + 'because Trakt|IMDB ID is missing. Skipping', {'show': show.name}) + continue + + try: + trakt_show = tv.TVShow(str(trakt_id or show.imdb_id)) + progress = trakt_show.progress + except TraktException as error: + log.info("Unable to check if show '{show}' is ended/completed. Error: {error!r}", { + 'show': show.name, + 'error': error + }) + continue + else: + if progress and progress.get('aired', True) == progress.get('completed', False): + app.show_queue_scheduler.action.removeShow(show, full=True) + log.info("Show '{show}' has being queued to be removed from Medusa library", { + 'show': show.name + }) def sync_trakt_shows(self): """Sync Trakt shows watchlist.""" if not self.show_watchlist: log.info('No shows found in your Trakt watchlist. Nothing to sync') - else: - trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER) + return - for watchlisted_show in self.show_watchlist: - trakt_show = watchlisted_show['show'] + trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER) - if trakt_show['year'] and trakt_show['ids']['slug'].endswith(str(trakt_show['year'])): - show_name = '{title} ({year})'.format(title=trakt_show['title'], year=trakt_show['year']) - else: - show_name = trakt_show['title'] - - show = None - indexer = None - for i in indexerConfig: - trakt_indexer = get_trakt_indexer(i) - indexer_id = trakt_show['ids'].get(trakt_indexer, -1) - indexer = indexerConfig[i]['id'] - show = Show.find_by_id(app.showList, indexer, indexer_id) - if show: - break - if not show: - # If can't find with available indexers try IMDB - trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB) - indexer_id = trakt_show['ids'].get(trakt_indexer, -1) - show = Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id) - if not show: - # If can't find with available indexers try TRAKT - trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT) - indexer_id = trakt_show['ids'].get(trakt_indexer, -1) - show = Show.find_by_id(app.showList, EXTERNAL_TRAKT, indexer_id) + for watchlisted_show in self.show_watchlist: + trakt_show = watchlisted_show['show'] + if trakt_show.year and trakt_show.ids['ids']['slug'].endswith(str(trakt_show['year'])): + show_name = '{title} ({year})'.format(title=trakt_show.title, year=trakt_show.year) + else: + show_name = trakt_show.title + + show = None + indexer = None + for i in indexerConfig: + trakt_indexer = get_trakt_indexer(i) + indexer_id = trakt_show.ids['ids'].get(trakt_indexer, -1) + indexer = indexerConfig[i]['id'] + show = Show.find_by_id(app.showList, indexer, indexer_id) if show: - continue + break + if not show: + # If can't find with available indexers try IMDB + trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB) + indexer_id = trakt_show.ids['ids'].get(trakt_indexer, -1) + show = Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id) + if not show: + # If can't find with available indexers try TRAKT + trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT) + indexer_id = trakt_show.ids['ids'].get(trakt_indexer, -1) + show = Show.find_by_id(app.showList, EXTERNAL_TRAKT, indexer_id) - indexer_id = trakt_show['ids'].get(get_trakt_indexer(trakt_default_indexer), -1) - if int(app.TRAKT_METHOD_ADD) != 2: - self.add_show(trakt_default_indexer, indexer_id, show_name, SKIPPED) - else: - self.add_show(trakt_default_indexer, indexer_id, show_name, WANTED) + if show: + continue - if int(app.TRAKT_METHOD_ADD) == 1 and indexer: - new_show = Show.find_by_id(app.showList, indexer, indexer_id) + indexer_id = trakt_show.ids['ids'].get(get_trakt_indexer(trakt_default_indexer), -1) + if int(app.TRAKT_METHOD_ADD) != 2: + self.add_show(trakt_default_indexer, indexer_id, show_name, SKIPPED) + else: + self.add_show(trakt_default_indexer, indexer_id, show_name, WANTED) - if new_show: - set_episode_to_wanted(new_show, 1, 1) - else: - log.warning('Unable to find the new added show.' - 'Pilot will be set to wanted in the next Trakt run') - self.todoWanted.append(indexer_id) - log.debug('Synced shows with Trakt watchlist') + if int(app.TRAKT_METHOD_ADD) == 1 and indexer: + new_show = Show.find_by_id(app.showList, indexer, indexer_id) + + if new_show: + set_episode_to_wanted(new_show, 1, 1) + else: + log.warning('Unable to find the new added show.' + 'Pilot will be set to wanted in the next Trakt run') + self.todo_wanted.append(indexer_id) + log.debug('Synced shows with Trakt watchlist') def sync_trakt_episodes(self): """Sync Trakt episodes watchlist.""" @@ -534,13 +560,17 @@ def sync_trakt_episodes(self): trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER) for watchlist_item in self.episode_watchlist: - trakt_show = watchlist_item['show'] - trakt_episode = watchlist_item['episode'].get('number', -1) - trakt_season = watchlist_item['episode'].get('season', -1) + trakt_show = watchlist_item.show + trakt_episode = watchlist_item.episode + trakt_season = watchlist_item.season show = None + for i in indexerConfig: trakt_indexer = get_trakt_indexer(i) + if not trakt_indexer: + continue + indexer_id = trakt_show['ids'].get(trakt_indexer, -1) indexer = indexerConfig[i]['id'] show = Show.find_by_id(app.showList, indexer, indexer_id) @@ -560,7 +590,8 @@ def sync_trakt_episodes(self): # If can't find show add with default trakt indexer if not show: - indexer_id = trakt_show['ids'].get(get_trakt_indexer(trakt_default_indexer), -1) + trakt_indexer = get_trakt_indexer(trakt_default_indexer) + indexer_id = trakt_show['ids'].get(trakt_indexer, -1) # Only add show if we didn't added it before if indexer_id not in added_shows: self.add_show(trakt_default_indexer, indexer_id, trakt_show['title'], SKIPPED) @@ -574,52 +605,54 @@ def sync_trakt_episodes(self): @staticmethod def add_show(indexer, indexer_id, show_name, status): """Add a new show with default settings.""" - if not Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id): - root_dirs = app.ROOT_DIRS + if Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id): + return - location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None + root_dirs = app.ROOT_DIRS - if location: - log.info("Adding show '{show}' using indexer: '{indexer_name}' and ID: {id}", { - 'show': show_name, - 'indexer_name': indexerConfig[indexer]['identifier'], - 'id': indexer_id - }) + location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None - allowed, preferred = Quality.split_quality(int(app.QUALITY_DEFAULT)) - quality = {'allowed': allowed, 'preferred': preferred} - - app.show_queue_scheduler.action.addShow(indexer, indexer_id, None, - default_status=status, - quality=quality, - season_folders=int(app.SEASON_FOLDERS_DEFAULT), - paused=app.TRAKT_START_PAUSED, - default_status_after=status, - root_dir=location) - tries = 0 - while tries < 3: - if Show.find_by_id(app.showList, indexer, indexer_id): - return - # Wait before show get's added and refreshed - time.sleep(60) - tries += 1 - log.warning("Error creating show '{show}. Please check logs' ", { - 'show': show_name - }) - return - else: - log.warning("Error creating show '{show}' folder. No default root directory", { - 'show': show_name - }) - return + if location: + log.info("Adding show '{show}' using indexer: '{indexer_name}' and ID: {id}", { + 'show': show_name, + 'indexer_name': indexerConfig[indexer]['identifier'], + 'id': indexer_id + }) + + allowed, preferred = Quality.split_quality(int(app.QUALITY_DEFAULT)) + quality = {'allowed': allowed, 'preferred': preferred} + + app.show_queue_scheduler.action.addShow(indexer, indexer_id, None, + default_status=status, + quality=quality, + season_folders=int(app.SEASON_FOLDERS_DEFAULT), + paused=app.TRAKT_START_PAUSED, + default_status_after=status, + root_dir=location) + tries = 0 + while tries < 3: + if Show.find_by_id(app.showList, indexer, indexer_id): + return + # Wait before show get's added and refreshed + time.sleep(60) + tries += 1 + log.warning("Error creating show '{show}. Please check logs' ", { + 'show': show_name + }) + return + else: + log.warning("Error creating show '{show}' folder. No default root directory", { + 'show': show_name + }) + return def manage_new_show(self, show): """Set episodes to wanted for the recently added show.""" log.debug("Checking for wanted episodes for show '{show}' in Trakt watchlist", {'show': show.name}) - episodes = [i for i in self.todoWanted if i[0] == show.indexerid] + episodes = [i for i in self.todo_wanted if i[0] == show.indexerid] for episode in episodes: - self.todoWanted.remove(episode) + self.todo_wanted.remove(episode) set_episode_to_wanted(show, episode[1], episode[2]) def _check_list(self, show_obj=None, indexer=None, indexer_id=None, season=None, episode=None, list_type=None): @@ -627,7 +660,7 @@ def _check_list(self, show_obj=None, indexer=None, indexer_id=None, season=None, if 'Collection' == list_type: trakt_indexer = get_trakt_indexer(indexer) for collected_show in self.collection_list: - if not collected_show['show']['ids'].get(trakt_indexer, '') == indexer_id: + if not getattr(collected_show, trakt_indexer) == indexer_id: continue if 'seasons' in collected_show: for season_item in collected_show['seasons']: @@ -641,33 +674,29 @@ def _check_list(self, show_obj=None, indexer=None, indexer_id=None, season=None, elif 'Show' == list_type: trakt_indexer = get_trakt_indexer(show_obj.indexer) for watchlisted_show in self.show_watchlist: - if watchlisted_show['show']['ids'].get(trakt_indexer) == show_obj.indexerid or \ - watchlisted_show['show']['ids'].get(get_trakt_indexer(EXTERNAL_IMDB), '') == show_obj.imdb_id: + if getattr(watchlisted_show, trakt_indexer) == show_obj.indexerid or \ + getattr(watchlisted_show, get_trakt_indexer(EXTERNAL_IMDB)) == show_obj.imdb_id: return True return False else: trakt_indexer = get_trakt_indexer(indexer) for watchlisted_episode in self.episode_watchlist: - if watchlisted_episode['episode'].get('season', -1) == season and \ - watchlisted_episode['episode'].get('number', -1) == episode and \ - watchlisted_episode['show']['ids'].get(trakt_indexer, '') == indexer_id: + if watchlisted_episode.season == season and \ + watchlisted_episode.episode == episode and \ + watchlisted_episode['ids'].get(trakt_indexer) == indexer_id: return True return False def _get_show_watchlist(self): """Get shows watchlist.""" - try: - self.show_watchlist = self._request('sync/watchlist/shows') - except (TraktException, AuthException, TokenExpiredException) as error: - log.info(u'Unable to retrieve shows from Trakt watchlist. Error: {error!r}', {'error': error}) - return False - return True + user = get_trakt_user() + return user.watchlist_shows def _get_episode_watchlist(self): """Get episodes watchlist.""" try: - self.episode_watchlist = self._request('sync/watchlist/episodes') - except (TraktException, AuthException, TokenExpiredException) as error: + self.episode_watchlist = sync.get_watchlist('episodes') + except TraktException as error: log.info(u'Unable to retrieve episodes from Trakt watchlist. Error: {error!r}', {'error': error}) return False return True @@ -675,8 +704,8 @@ def _get_episode_watchlist(self): def _get_show_collection(self): """Get show collection.""" try: - self.collection_list = self._request('sync/collection/shows') - except (TraktException, AuthException, TokenExpiredException) as error: + self.collection_list = sync.get_collection('shows') + except TraktException as error: log.info('Unable to retrieve shows from Trakt collection. Error: {error!r}', {'error': error}) return False return True diff --git a/medusa/search/core.py b/medusa/search/core.py index 9aed48f799..6d9260ee02 100644 --- a/medusa/search/core.py +++ b/medusa/search/core.py @@ -188,10 +188,10 @@ def snatch_episode(result): for cur_ep_obj in result.episodes: with cur_ep_obj.lock: if is_first_best_match(result): - cur_ep_obj.status = SNATCHED_BEST + cur_ep_obj._status = SNATCHED_BEST cur_ep_obj.quality = result.quality else: - cur_ep_obj.status = end_status + cur_ep_obj._status = end_status cur_ep_obj.quality = result.quality # Reset all others fields to the snatched status # New snatch by default doesn't have nfo/tbn @@ -222,7 +222,7 @@ def snatch_episode(result): notifiers.notify_snatch(cur_ep_obj, result) if app.USE_TRAKT and app.TRAKT_SYNC_WATCHLIST: - trakt_data.append((cur_ep_obj.season, cur_ep_obj.episode)) + trakt_data.append(cur_ep_obj) log.info( u'Adding {0} {1} to Trakt watchlist', result.series.name, @@ -230,9 +230,8 @@ def snatch_episode(result): ) if trakt_data: - data_episode = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) - if data_episode: - notifiers.trakt_notifier.update_watchlist(result.series, data_episode=data_episode, update=u'add') + for episode in trakt_data: + notifiers.trakt_notifier.add_episode_to_watchlist(episode) if sql_l: main_db_con = db.DBConnection() diff --git a/medusa/server/web/home/add_shows.py b/medusa/server/web/home/add_shows.py index 995937c801..eb37ce0d47 100644 --- a/medusa/server/web/home/add_shows.py +++ b/medusa/server/web/home/add_shows.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals -import datetime import json import logging @@ -11,6 +10,7 @@ from medusa.helper.common import try_int from medusa.helpers import get_showname_from_indexer from medusa.helpers.anidb import short_group_names +from medusa.helpers.trakt import get_trakt_user from medusa.indexers.config import INDEXER_TVDBV2 from medusa.logger.adapters.style import BraceAdapter from medusa.server.web.core import PageTemplate @@ -28,7 +28,8 @@ from tornroutes import route -from traktor import TraktApi +from trakt.errors import TraktException + log = BraceAdapter(logging.getLogger(__name__)) log.logger.addHandler(logging.NullHandler()) @@ -130,31 +131,10 @@ def getTrendingShows(self, traktList=None): if traktList is None: traktList = '' - traktList = traktList.lower() - - if traktList == 'trending': - page_url = 'shows/trending' - elif traktList == 'popular': - page_url = 'shows/popular' - elif traktList == 'anticipated': - page_url = 'shows/anticipated' - elif traktList == 'collected': - page_url = 'shows/collected' - elif traktList == 'watched': - page_url = 'shows/watched' - elif traktList == 'played': - page_url = 'shows/played' - elif traktList == 'recommended': - page_url = 'recommendations/shows' - elif traktList == 'newshow': - page_url = 'calendars/all/shows/new/%s/30' % datetime.date.today().strftime('%Y-%m-%d') - elif traktList == 'newseason': - page_url = 'calendars/all/shows/premieres/%s/30' % datetime.date.today().strftime('%Y-%m-%d') - else: - page_url = 'shows/anticipated' + trakt_list = traktList.lower() try: - (trakt_blacklist, recommended_shows, removed_from_medusa) = TraktPopular().fetch_popular_shows(page_url=page_url, trakt_list=traktList) + (trakt_blacklist, recommended_shows, removed_from_medusa) = TraktPopular().fetch_popular_shows(trakt_list) except Exception as e: error = e @@ -201,23 +181,36 @@ def addShowToBlacklist(self, seriesid): # URL parameters data = {'shows': [{'ids': {'tvdb': seriesid}}]} - trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - show_name = get_showname_from_indexer(INDEXER_TVDBV2, seriesid) try: - trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings) - trakt_api.request('users/{0}/lists/{1}/items'.format - (app.TRAKT_USERNAME, app.TRAKT_BLACKLIST_NAME), data, method='POST') + trakt_user = get_trakt_user() + blacklist = trakt_user.get_list(app.TRAKT_BLACKLIST_NAME) + + if not blacklist: + ui.notifications.error( + 'Warning', + 'Could not find blacklist {blacklist} for user {user}.'.format( + blacklist=app.TRAKT_BLACKLIST_NAME, user=trakt_user.username + ) + ) + log.warning( + 'Could not find blacklist {blacklist} for user {user}.', + {'blacklist': app.TRAKT_BLACKLIST_NAME, 'user': trakt_user.username} + ) + + # Add the show to the blacklist. + blacklist.add_items(data) + ui.notifications.message('Success!', "Added show '{0}' to blacklist".format(show_name)) - except Exception as e: + except TraktException as error: ui.notifications.error('Error!', "Unable to add show '{0}' to blacklist. Check logs.".format(show_name)) log.warning("Error while adding show '{name}' to trakt blacklist: {error}", - {'name': show_name, 'error': e}) + {'name': show_name, 'error': error}) + + except Exception as error: + log.exception('Error trying to add show to blacklist, error: {error}', {'error': error}) def existingShows(self): """ diff --git a/medusa/server/web/home/handler.py b/medusa/server/web/home/handler.py index 98ea5cbdb7..83c99deecd 100644 --- a/medusa/server/web/home/handler.py +++ b/medusa/server/web/home/handler.py @@ -93,12 +93,8 @@ from tornroutes import route -from traktor import ( - MissingTokenException, - TokenExpiredException, - TraktApi, - TraktException, -) +import trakt +from trakt.errors import TraktException @route('/home(/?.*)') @@ -452,38 +448,59 @@ def settingsNMJv2(host=None, dbloc=None, instance=None): }) @staticmethod - def getTraktToken(trakt_pin=None): - trakt_settings = {'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_api_secret': app.TRAKT_API_SECRET} - trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) - response = None + def requestTraktDeviceCodeOauth(): + """Start Trakt OAuth device auth. Send request.""" + logger.log('Start a new Oauth device authentication request. Request is valid for 60 minutes.', logger.INFO) try: - (access_token, refresh_token) = trakt_api.get_token(app.TRAKT_REFRESH_TOKEN, trakt_pin=trakt_pin) - if access_token and refresh_token: - app.TRAKT_ACCESS_TOKEN = access_token - app.TRAKT_REFRESH_TOKEN = refresh_token - response = trakt_api.validate_account() - except MissingTokenException: - ui.notifications.error('You need to get a PIN and authorize Medusa app') - return 'You need to get a PIN and authorize Medusa app' - except TokenExpiredException: - # Clear existing tokens - app.TRAKT_ACCESS_TOKEN = '' - app.TRAKT_REFRESH_TOKEN = '' - ui.notifications.error('TOKEN expired. Reload page, get a new PIN and authorize Medusa app') - return 'TOKEN expired. Reload page, get a new PIN and authorize Medusa app' - except TraktException: - ui.notifications.error("Connection error. Click 'Authorize Medusa' button again") - return "Connection error. Click 'Authorize Medusa' button again" - if response: - ui.notifications.message('Trakt Authorized') - return 'Trakt Authorized' - ui.notifications.error('Connection error. Reload the page to get new token!') - return 'Trakt Not Authorized!' + app.TRAKT_DEVICE_CODE = trakt.get_device_code(app.TRAKT_API_KEY, app.TRAKT_API_SECRET) + except TraktException as error: + logger.log('Unable to get trakt device code. Error: {error!r}'.format(error=error), logger.WARNING) + return json.dumps({'result': False}) + + return json.dumps(app.TRAKT_DEVICE_CODE) @staticmethod - def testTrakt(username=None, blacklist_name=None): - return notifiers.trakt_notifier.test_notify(username, blacklist_name) + def checkTrakTokenOauth(): + """Check if the Trakt device OAuth request has been authenticated.""" + logger.log('Start Trakt token request', logger.INFO) + + if not app.TRAKT_DEVICE_CODE.get('requested'): + logger.log('You need to request a token before checking authentication', logger.WARNING) + return json.dumps({'result': 'need to request first', 'error': True}) + + if (app.TRAKT_DEVICE_CODE.get('requested') + app.TRAKT_DEVICE_CODE.get('requested')) < time.time(): + logger.log('Trakt token Request expired', logger.INFO) + return json.dumps({'result': 'request expired', 'error': True}) + + if not app.TRAKT_DEVICE_CODE.get('device_code'): + logger.log('You need to request a token before checking authentication. Missing device code.', logger.WARNING) + return json.dumps({'result': 'need to request first', 'error': True}) + + try: + response = trakt.get_device_token( + app.TRAKT_DEVICE_CODE.get('device_code'), app.TRAKT_API_KEY, app.TRAKT_API_SECRET, store=True + ) + except TraktException as error: + logger.log('Unable to get trakt device token. Error: {error!r}'.format(error=error), logger.WARNING) + return json.dumps({'result': 'Trakt error while retrieving device token', 'error': True}) + + if response.ok: + response_json = response.json() + app.TRAKT_ACCESS_TOKEN, app.TRAKT_REFRESH_TOKEN = \ + response_json.get('access_token'), response_json.get('refresh_token') + return json.dumps({'result': 'succesfully updated trakt access and refresh token', 'error': False}) + else: + if response.status_code == 400: + return json.dumps({'result': 'device code has not been activated yet', 'error': True}) + if response.status_code == 409: + return json.dumps({'result': 'already activated this code', 'error': False}) + + logger.log(u'Something went wrong', logger.DEBUG) + return json.dumps({'result': 'Something went wrong'}) + + @staticmethod + def testTrakt(blacklist_name=None): + return notifiers.trakt_notifier.test_notify(blacklist_name) @staticmethod def forceTraktSync(): @@ -1236,6 +1253,7 @@ def updateEMBY(self, indexername=None, seriesid=None): def setStatus(self, indexername=None, seriesid=None, eps=None, status=None, direct=False): # @TODO: Merge this with the other PUT commands for /api/v2/show/{id} + # Still used by manage/changeEpisodeStatuses (manage_episodeStatuses.mako) if not all([indexername, seriesid, eps, status]): error_message = 'You must specify a show and at least one episode' if direct: @@ -1336,14 +1354,12 @@ def setStatus(self, indexername=None, seriesid=None, eps=None, status=None, dire # Only in failed_history we set to FAILED. if status != FAILED: - ep_obj.status = status + ep_obj._status = status # mass add to database sql_l.append(ep_obj.get_sql()) - trakt_data.append((ep_obj.season, ep_obj.episode)) - - data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) + trakt_data.append(ep_obj.season) if app.USE_TRAKT and app.TRAKT_SYNC_WATCHLIST: if status in [WANTED, FAILED]: @@ -1354,8 +1370,9 @@ def setStatus(self, indexername=None, seriesid=None, eps=None, status=None, dire logger.log('{action} episodes, showid: indexerid {show.indexerid}, Title {show.name} to Watchlist'.format( action=upd, show=series_obj), logger.DEBUG) - if data: - notifiers.trakt_notifier.update_watchlist(series_obj, data_episode=data, update=upd.lower()) + if trakt_data: + for ep_obj in trakt_data: + notifiers.trakt_notifier.update_watchlist_episode(ep_obj) if sql_l: main_db_con = db.DBConnection() diff --git a/medusa/show/recommendations/trakt.py b/medusa/show/recommendations/trakt.py index 5d15f6eb18..2a68a25ba1 100644 --- a/medusa/show/recommendations/trakt.py +++ b/medusa/show/recommendations/trakt.py @@ -1,3 +1,4 @@ +"""Trakt recommendations module.""" # coding=utf-8 from __future__ import unicode_literals @@ -10,6 +11,7 @@ from medusa.cache import recommended_series_cache from medusa.helper.common import try_int from medusa.helper.exceptions import MultipleShowObjectsException +from medusa.helpers.trakt import get_trakt_show_collection, get_trakt_user from medusa.indexers.api import indexerApi from medusa.indexers.config import INDEXER_TVDBV2 from medusa.logger.adapters.style import BraceAdapter @@ -19,9 +21,7 @@ create_key_from_series, ) -from six import text_type - -from traktor import (TokenExpiredException, TraktApi, TraktException) +from trakt import sync from tvdbapiv2.exceptions import ApiException @@ -47,37 +47,38 @@ def __init__(self): self.tvdb_api_v2 = indexerApi(INDEXER_TVDBV2).indexer() @recommended_series_cache.cache_on_arguments(namespace='trakt', function_key_generator=create_key_from_series) - def _create_recommended_show(self, storage_key, series): + def _create_recommended_show(self, storage_key, show): """Create the RecommendedShow object from the returned showobj.""" rec_show = RecommendedShow( self, - series['show']['ids'], series['show']['title'], + show.tvdb, + show.title, INDEXER_TVDBV2, # indexer - series['show']['ids']['tvdb'], - **{'rating': series['show']['rating'], - 'votes': try_int(series['show']['votes'], '0'), - 'image_href': 'http://www.trakt.tv/shows/{0}'.format(series['show']['ids']['slug']), + show.tvdb, + **{'rating': show.ratings['rating'], + 'votes': try_int(show.ratings['votes'], '0'), + 'image_href': 'http://www.trakt.tv/shows/{0}'.format(show.ids['ids']['slug']), # Adds like: {'tmdb': 62126, 'tvdb': 304219, 'trakt': 79382, 'imdb': 'tt3322314', # 'tvrage': None, 'slug': 'marvel-s-luke-cage'} - 'ids': series['show']['ids'] + 'ids': show.ids['ids'] } ) use_default = None image = None try: - if not missing_posters.has(series['show']['ids']['tvdb']): - image = self.check_cache_for_poster(series['show']['ids']['tvdb']) or \ + if not missing_posters.has(show.tvdb): + image = self.check_cache_for_poster(show.tvdb) or \ self.tvdb_api_v2.config['session'].series_api.series_id_images_query_get( - series['show']['ids']['tvdb'], key_type='poster').data[0].file_name + show.tvdb, key_type='poster').data[0].file_name else: - log.info('CACHE: Missing poster on TVDB for show {0}', series['show']['title']) + log.info('CACHE: Missing poster on TVDB for show {0}', show.title) use_default = self.default_img_src except ApiException as error: use_default = self.default_img_src if getattr(error, 'status', None) == 404: - log.info('Missing poster on TheTVDB for show {0}', series['show']['title']) - missing_posters.append(series['show']['ids']['tvdb']) + log.info('Missing poster on TheTVDB for show {0}', show.title) + missing_posters.append(show.tvdb) except Exception as error: use_default = self.default_img_src log.debug('Missing poster on TheTVDB, cause: {0!r}', error) @@ -91,27 +92,12 @@ def _create_recommended_show(self, storage_key, series): # As the method below requires a lot of resources, i've only enabled it when # the shows language or country is 'jp' (japanese). Looks a litle bit akward, # but alternative is a lot of resource used - if 'jp' in [series['show']['country'], series['show']['language']]: - rec_show.flag_as_anime(series['show']['ids']['tvdb']) + if 'jp' in [show.country, show.language]: + rec_show.flag_as_anime(show.tvdb) return rec_show - @staticmethod - def fetch_and_refresh_token(trakt_api, path): - """Fetch shows from trakt and store the refresh token when needed.""" - try: - library_shows = trakt_api.request(path) or [] - if trakt_api.access_token_refreshed: - app.TRAKT_ACCESS_TOKEN = trakt_api.access_token - app.TRAKT_REFRESH_TOKEN = trakt_api.refresh_token - app.instance.save_config() - except TokenExpiredException: - app.TRAKT_ACCESS_TOKEN = '' - raise - - return library_shows - - def fetch_popular_shows(self, page_url=None, trakt_list=None): + def fetch_popular_shows(self, trakt_list=None): """Get a list of popular shows from different Trakt lists based on a provided trakt_list. :param page_url: the page url opened to the base api url, for retreiving a specific list @@ -122,55 +108,41 @@ def fetch_popular_shows(self, page_url=None, trakt_list=None): trending_shows = [] removed_from_medusa = [] - # Create a trakt settings dict - trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET, - 'trakt_api_key': app.TRAKT_API_KEY, - 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, - 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN} - - trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings) - try: not_liked_show = '' - if app.TRAKT_ACCESS_TOKEN != '': - library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \ - self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full') - - medusa_shows = [show.indexerid for show in app.showList if show.indexerid] - removed_from_medusa = [lshow['show']['ids']['tvdb'] for lshow in library_shows if lshow['show']['ids']['tvdb'] not in medusa_shows] + library_shows = sync.get_watched('shows', extended='noseasons') + sync.get_collection('shows', extended='full') + medusa_shows = [show.indexerid for show in app.showList if show.indexerid] + removed_from_medusa = [lshow.tvdb for lshow in library_shows if lshow.tvdb not in medusa_shows] - if app.TRAKT_BLACKLIST_NAME is not None and app.TRAKT_BLACKLIST_NAME: - not_liked_show = trakt_api.request('users/' + app.TRAKT_USERNAME + '/lists/' + - app.TRAKT_BLACKLIST_NAME + '/items') or [] - else: - log.debug('Trakt blacklist name is empty') + if app.TRAKT_BLACKLIST_NAME: + trakt_user = get_trakt_user() + not_liked_show = trakt_user.get_list(app.TRAKT_BLACKLIST_NAME) or [] + else: + log.debug('Trakt blacklist name is empty') + limit = None if trakt_list not in ['recommended', 'newshow', 'newseason']: - limit_show = '?limit=' + text_type(100 + len(not_liked_show)) + '&' - else: - limit_show = '?' + limit = 100 + len(not_liked_show) - series = self.fetch_and_refresh_token(trakt_api, page_url + limit_show + 'extended=full,images') or [] + # Get the trakt list + shows = get_trakt_show_collection(trakt_list, limit) - # Let's trigger a cache cleanup. + # Trigger a cache cleanup missing_posters.clean() - for show in series: + for show in shows: try: # If there isn't a tvdb id available skip it. We can't add it anyway. - if show['show']['ids']['tvdb'] is None: + if show.tvdb is None: continue - if 'show' not in show: - show['show'] = show - - if not_liked_show and show['show']['ids']['tvdb'] in (s['show']['ids']['tvdb'] - for s in not_liked_show if s['type'] == 'show'): + if (not_liked_show and show.tvdb + in (s.tvdb for s in not_liked_show if s.media_type == 'shows')): continue trending_shows.append(self._create_recommended_show( - storage_key=show['show']['ids']['trakt'], - series=show + storage_key=show.trakt, + show=show )) except MultipleShowObjectsException: @@ -179,8 +151,8 @@ def fetch_popular_shows(self, page_url=None, trakt_list=None): # Update the dogpile index. This will allow us to retrieve all stored dogpile shows from the dbm. blacklist = app.TRAKT_BLACKLIST_NAME not in '' - except TraktException as error: - log.warning('Could not connect to Trakt service: {0}', error) + except Exception as error: + log.exception('Could not connect to Trakt service: {0}', error) raise return blacklist, trending_shows, removed_from_medusa @@ -192,6 +164,6 @@ def check_cache_for_poster(self, tvdb_id): for image_file_name in os.listdir(os.path.abspath(os.path.join(app.CACHE_DIR, 'images', self.cache_subfolder))): if os.path.isfile(os.path.abspath(os.path.join(app.CACHE_DIR, 'images', self.cache_subfolder, image_file_name))): - if text_type(tvdb_id) == image_file_name.split('-')[0]: + if str(tvdb_id) == image_file_name.split('-')[0]: return image_file_name return False diff --git a/medusa/tv/episode.py b/medusa/tv/episode.py index 5200469dc4..15a011cbc9 100644 --- a/medusa/tv/episode.py +++ b/medusa/tv/episode.py @@ -27,6 +27,8 @@ from medusa.common import ( ARCHIVED, DOWNLOADED, + FAILED, + IGNORED, NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, @@ -251,7 +253,7 @@ def __init__(self, series, season, episode, filepath=''): self.airdate = date.fromordinal(1) self.hasnfo = False self.hastbn = False - self.status = UNSET + self._status = UNSET self.quality = Quality.NA self.file_size = 0 self.release_name = '' @@ -422,6 +424,38 @@ def air_date(self): return date_parsed.isoformat() + @property + def status(self): + """Return the episode status.""" + return self._status + + @status.setter + def status(self, value): + self._status = value + self._sync_trakt(value) + + def _sync_trakt(self, status): + """If Trakt enabled and trakt sync watchlist enabled, add/remove the episode from the watchlist.""" + if app.USE_TRAKT and app.TRAKT_SYNC_WATCHLIST: + + upd = None + if status in [WANTED, FAILED]: + upd = 'Add' + + elif status in [IGNORED, SKIPPED, DOWNLOADED, ARCHIVED]: + upd = 'Remove' + + if not upd: + return + + log.debug('{action} episode {episode}, showid: indexerid {show_id},' + 'Title {show_name} to Watchlist', { + 'action': upd, 'episode': self.episode, + 'show_id': self.series.series_id, 'show_name': self.series.name + }) + + notifiers.trakt_notifier.update_watchlist_episode(self) + @property def status_name(self): """Return the status name.""" @@ -689,7 +723,7 @@ def load_from_db(self, season, episode): self.subtitles_searchcount = sql_results[0]['subtitles_searchcount'] self.subtitles_lastsearch = sql_results[0]['subtitles_lastsearch'] self.airdate = date.fromordinal(int(sql_results[0]['airdate'])) - self.status = int(sql_results[0]['status'] or UNSET) + self._status = int(sql_results[0]['status'] or UNSET) self.quality = int(sql_results[0]['quality'] or Quality.NA) self.watched = bool(sql_results[0]['watched']) @@ -943,7 +977,7 @@ def load_from_indexer(self, season=None, episode=None, tvapi=None, cached_season # If is a leaked episode and user manually snatched, it will respect status # If is a fake (manually snatched), when user set as FAILED, status will be WANTED # and code below will make it UNAIRED again - self.status = UNAIRED + self._status = UNAIRED log.debug( '{id}: {series} {ep} airs in the future or has no air date, marking it {status}', { 'id': self.series.series_id, @@ -955,7 +989,7 @@ def load_from_indexer(self, season=None, episode=None, tvapi=None, cached_season elif self.status in (UNSET, UNAIRED): # Only do UNAIRED/UNSET, it could already be snatched/ignored/skipped, # or downloaded/archived to disconnected media - self.status = self.series.default_ep_status if self.season > 0 else SKIPPED # auto-skip specials + self._status = self.series.default_ep_status if self.season > 0 else SKIPPED # auto-skip specials log.debug( '{id}: {series} {ep} has already aired, marking it {status}', { 'id': self.series.series_id, @@ -996,7 +1030,7 @@ def load_from_indexer(self, season=None, episode=None, tvapi=None, cached_season 'old_status': statusStrings[self.status], } ) - self.status = UNSET + self._status = UNSET self.save_to_db() @@ -2103,7 +2137,7 @@ def update_status_quality(self, filepath): new_status = ARCHIVED with self.lock: - self.status = new_status + self._status = new_status self.quality = new_quality if not same_name: diff --git a/medusa/tv/series.py b/medusa/tv/series.py index 3e4e9fdd7d..1c30ca8dd3 100644 --- a/medusa/tv/series.py +++ b/medusa/tv/series.py @@ -1901,7 +1901,7 @@ def delete_show(self, full=False): if app.USE_TRAKT and app.TRAKT_SYNC_WATCHLIST: log.debug(u'{id}: Removing show {show} from Trakt watchlist', {'id': self.series_id, 'show': self.name}) - notifiers.trakt_notifier.update_watchlist(self, update='remove') + notifiers.trakt_notifier.update_watchlist_show(self, remove=True) def populate_cache(self): """Populate image caching.""" @@ -1921,7 +1921,7 @@ def sync_trakt(self): if app.TRAKT_SYNC_WATCHLIST: log.info('updating trakt watchlist') - notifiers.trakt_notifier.update_watchlist(show_obj=self) + notifiers.trakt_notifier.update_watchlist_show(self) def add_scene_numbering(self): """ @@ -1996,8 +1996,8 @@ def refresh_dir(self): continue # if the path doesn't exist or if it's not in our show dir - if (not os.path.isfile(cur_loc) or - not os.path.normpath(cur_loc).startswith(os.path.normpath(self.location))): + if (not os.path.isfile(cur_loc) + or not os.path.normpath(cur_loc).startswith(os.path.normpath(self.location))): # check if downloaded files still exist, update our data if this has changed if not app.SKIP_REMOVED_FILES: @@ -2019,7 +2019,7 @@ def refresh_dir(self): } ) - cur_ep.status = new_status + cur_ep._status = new_status cur_ep.subtitles = '' cur_ep.subtitles_searchcount = 0 cur_ep.subtitles_lastsearch = '' @@ -2656,7 +2656,7 @@ def set_all_episodes_archived(self, final_status_only=False): if final_status_only and Quality.should_search(ep_obj.status, ep_obj.quality, self, ep_obj.manually_searched)[0]: continue - ep_obj.status = ARCHIVED + ep_obj._status = ARCHIVED sql_list.append(ep_obj.get_sql()) if sql_list: main_db_con = db.DBConnection() diff --git a/requirements.txt b/requirements.txt index 00aa4d0a2d..a3f7bd4de3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,6 +35,7 @@ subliminal==2.1.0 tmdbsimple==2.7.0 tornado==5.1.1 tornroutes==0.5.1 +trakt==2.14.1 ttl-cache==1.6 tvdbapiv2 @ https://codeload.github.com/pymedusa/tvdbv2/tar.gz/bf1272c9264c280c3048e89a1920e2bf5f386284 validators==0.15.0 diff --git a/themes-default/slim/src/components/config-notifications.vue b/themes-default/slim/src/components/config-notifications.vue index b9eae52b36..ea04a424d5 100644 --- a/themes-default/slim/src/components/config-notifications.vue +++ b/themes-default/slim/src/components/config-notifications.vue @@ -784,6 +784,7 @@
+

Trakt

@@ -795,13 +796,11 @@
- - - - - - -

PIN code to authorize Medusa to access Trakt on your behalf.

+ + + Use this code in the popup: {{traktUserCode}} +

Trakt request status: {{traktRequestMessage}}

+

{{traktRequestMessage}}

@@ -820,8 +819,7 @@ 'Kodi detects that the episode was deleted and removes from collection which causes Medusa to re-add it. This causes a loop between Medusa and Kodi adding and deleting the episode.']" @change="save()" />
- +
{ "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 _api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api.js */ \"./src/api.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.mjs\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./src/components/helpers/index.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n name: 'config-notifications',\n components: {\n AppLink: _helpers__WEBPACK_IMPORTED_MODULE_1__.AppLink,\n ConfigTemplate: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTemplate,\n ConfigTextbox: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextbox,\n ConfigTextboxNumber: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextboxNumber,\n ConfigToggleSlider: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigToggleSlider,\n SelectList: _helpers__WEBPACK_IMPORTED_MODULE_1__.SelectList,\n ShowSelector: _helpers__WEBPACK_IMPORTED_MODULE_1__.ShowSelector\n },\n\n data() {\n return {\n prowlSelectedShow: null,\n prowlSelectedShowApiKeys: [],\n prowlPriorityOptions: [{\n text: 'Very Low',\n value: -2\n }, {\n text: 'Moderate',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverPriorityOptions: [{\n text: 'Lowest',\n value: -2\n }, {\n text: 'Low',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverSoundOptions: [{\n text: 'Default',\n value: 'default'\n }, {\n text: 'Pushover',\n value: 'pushover'\n }, {\n text: 'Bike',\n value: 'bike'\n }, {\n text: 'Bugle',\n value: 'bugle'\n }, {\n text: 'Cash Register',\n value: 'cashregister'\n }, {\n text: 'classical',\n value: 'classical'\n }, {\n text: 'Cosmic',\n value: 'cosmic'\n }, {\n text: 'Falling',\n value: 'falling'\n }, {\n text: 'Gamelan',\n value: 'gamelan'\n }, {\n text: 'Incoming',\n value: 'incoming'\n }, {\n text: 'Intermission',\n value: 'intermission'\n }, {\n text: 'Magic',\n value: 'magic'\n }, {\n text: 'Mechanical',\n value: 'mechanical'\n }, {\n text: 'Piano Bar',\n value: 'pianobar'\n }, {\n text: 'Siren',\n value: 'siren'\n }, {\n text: 'Space Alarm',\n value: 'spacealarm'\n }, {\n text: 'Tug Boat',\n value: 'tugboat'\n }, {\n text: 'Alien Alarm (long)',\n value: 'alien'\n }, {\n text: 'Climb (long)',\n value: 'climb'\n }, {\n text: 'Persistent (long)',\n value: 'persistant'\n }, {\n text: 'Pushover Echo (long)',\n value: 'echo'\n }, {\n text: 'Up Down (long)',\n value: 'updown'\n }, {\n text: 'None (silent)',\n value: 'none'\n }],\n pushbulletDeviceOptions: [{\n text: 'All devices',\n value: ''\n }],\n traktMethodOptions: [{\n text: 'Skip all',\n value: 0\n }, {\n text: 'Download pilot only',\n value: 1\n }, {\n text: 'Get whole show',\n value: 2\n }],\n pushbulletTestInfo: 'Click below to test.',\n joinTestInfo: 'Click below to test.',\n twitterTestInfo: 'Click below to test.',\n twitterKey: '',\n emailSelectedShow: null,\n emailSelectedShowAdresses: [],\n saving: false\n };\n },\n\n computed: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapState)({\n config: state => state.config.general,\n indexers: state => state.config.indexers,\n notifiers: state => state.config.notifiers\n }),\n\n traktNewTokenMessage() {\n const {\n accessToken\n } = this.notifiers.trakt;\n return 'Get ' + accessToken ? 'New ' : 0;\n },\n\n traktIndexersOptions() {\n const {\n indexers\n } = this;\n const {\n traktIndexers\n } = indexers.main;\n const validTraktIndexer = Object.keys(indexers.indexers).filter(k => traktIndexers[k]);\n return validTraktIndexer.map(indexer => {\n return {\n text: indexer,\n value: indexers.indexers[indexer].id\n };\n });\n }\n\n },\n\n beforeMount() {\n // Wait for the next tick, so the component is rendered\n this.$nextTick(() => {\n $('#config-components').tabs();\n });\n },\n\n mounted() {\n // TODO: vueify this.\n $('#trakt_pin').on('keyup change', () => {\n if ($('#trakt_pin').val().length === 0) {\n $('#TraktGetPin').removeClass('hide');\n $('#authTrakt').addClass('hide');\n } else {\n $('#TraktGetPin').addClass('hide');\n $('#authTrakt').removeClass('hide');\n }\n });\n },\n\n methods: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapActions)(['getShows', 'setConfig']),\n\n onChangeProwlApi(items) {\n this.notifiers.prowl.api = items.map(item => item.value);\n },\n\n savePerShowNotifyList(listType, values) {\n const {\n emailSelectedShow,\n prowlSelectedShow\n } = this;\n const form = new FormData();\n\n if (listType === 'prowl') {\n form.set('show', prowlSelectedShow);\n form.set('prowlAPIs', values.map(apiKey => apiKey.value));\n } else {\n form.set('show', emailSelectedShow);\n form.set('emails', values.map(apiKey => apiKey.value));\n } // Save the list\n\n\n _api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute.post('home/saveShowNotifyList', form);\n },\n\n async prowlUpdateApiKeys(selectedShow) {\n this.prowlSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].prowl_notify_list ? response.data[selectedShow].prowl_notify_list.split(',') : [];\n this.prowlSelectedShowApiKeys = selectedShow ? list : [];\n }\n },\n\n async emailUpdateShowEmail(selectedShow) {\n this.emailSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].list ? response.data[selectedShow].list.split(',') : [];\n this.emailSelectedShowAdresses = selectedShow ? list : [];\n }\n },\n\n emailUpdateAddressList(items) {\n this.notifiers.email.addressList = items.map(x => x.value);\n },\n\n async getPushbulletDeviceOptions() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/getPushbulletDevices', {\n params: {\n api: pushbulletApiKey\n }\n });\n const options = [];\n const {\n data\n } = response;\n\n if (!data) {\n return false;\n }\n\n options.push({\n text: 'All devices',\n value: ''\n });\n\n for (const device of data.devices) {\n if (device.active === true) {\n options.push({\n text: device.nickname,\n value: device.iden\n });\n }\n }\n\n this.pushbulletDeviceOptions = options;\n this.pushbulletTestInfo = 'Device list updated. Please choose a device to push to.';\n },\n\n async testPushbulletApi() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testPushbullet', {\n params: {\n api: pushbulletApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.pushbulletTestInfo = data;\n }\n },\n\n async testJoinApi() {\n const {\n api: joinApiKey\n } = this.notifiers.join;\n\n if (!joinApiKey) {\n this.joinTestInfo = 'You didn\\'t supply a Join api key';\n $('#join_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testJoin', {\n params: {\n api: joinApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.joinTestInfo = data;\n }\n },\n\n async twitterStep1() {\n this.twitterTestInfo = MEDUSA.config.layout.loading;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep1');\n const {\n data\n } = response;\n window.open(data);\n this.twitterTestInfo = 'Step1: Confirm Authorization';\n },\n\n async twitterStep2() {\n const twitter = {};\n const {\n twitterKey\n } = this;\n twitter.key = twitterKey;\n\n if (twitter.key) {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep2', {\n params: {\n key: twitter.key\n }\n });\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } else {\n this.twitterTestInfo = 'Please fill out the necessary fields above.';\n }\n },\n\n async twitterTest() {\n try {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testTwitter');\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } catch (error) {\n this.twitterTestInfo = 'Error while trying to request for a test on the twitter api.';\n }\n },\n\n async save() {\n const {\n notifiers,\n setConfig\n } = this; // Disable the save button until we're done.\n\n this.saving = true;\n const section = 'main';\n\n try {\n await setConfig({\n section,\n config: {\n notifiers\n }\n });\n this.$snotify.success('Saved Notifiers config', 'Saved', {\n timeout: 5000\n });\n } catch (error) {\n this.$snotify.error('Error while trying to save notifiers config', 'Error');\n } finally {\n this.saving = false;\n }\n },\n\n testGrowl() {\n const growl = {};\n growl.host = $.trim($('#growl_host').val());\n growl.password = $.trim($('#growl_password').val());\n\n if (!growl.host) {\n $('#testGrowl-result').html('Please fill out the necessary fields above.');\n $('#growl_host').addClass('warning');\n return;\n }\n\n $('#growl_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testGrowl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testGrowl', {\n host: growl.host,\n password: growl.password\n }).done(data => {\n $('#testGrowl-result').html(data);\n $('#testGrowl').prop('disabled', false);\n });\n },\n\n testProwl() {\n const prowl = {};\n prowl.api = $.trim($('#prowl_api').find('input').val());\n prowl.priority = $('#prowl_priority').find('input').val();\n\n if (!prowl.api) {\n $('#testProwl-result').html('Please fill out the necessary fields above.');\n $('#prowl_api').find('input').addClass('warning');\n return;\n }\n\n $('#prowl_api').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testProwl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testProwl', {\n prowl_api: prowl.api,\n // eslint-disable-line camelcase\n prowl_priority: prowl.priority // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testProwl-result').html(data);\n $('#testProwl').prop('disabled', false);\n });\n },\n\n testKODI() {\n const kodi = {};\n const kodiHostInput = $('#kodi_host').find('input');\n const kodiHosts = kodiHostInput.toArray().map(value => value.value).filter(item => item !== '');\n kodi.host = kodiHosts.join(',');\n kodi.username = $.trim($('#kodi_username').val());\n kodi.password = $.trim($('#kodi_password').val());\n\n if (!kodi.host) {\n $('#testKODI-result').html('Please fill out the necessary fields above.');\n $('#kodi_host').find('input').addClass('warning');\n return;\n }\n\n $('#kodi_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testKODI-result').html(MEDUSA.config.layout.loading);\n $.get('home/testKODI', {\n host: kodi.host,\n username: kodi.username,\n password: kodi.password\n }).done(data => {\n $('#testKODI-result').html(data);\n $('#testKODI').prop('disabled', false);\n });\n },\n\n testPHT() {\n const plex = {};\n plex.client = {};\n const plexHostsInput = $('#plex_client_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.client.host = plexHosts.join(',');\n plex.client.username = $.trim($('#plex_client_username').val());\n plex.client.password = $.trim($('#plex_client_password').val());\n\n if (!plex.client.host) {\n $('#testPHT-result').html('Please fill out the necessary fields above.');\n $('#plex_client_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_client_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPHT-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPHT', {\n host: plex.client.host,\n username: plex.client.username,\n password: plex.client.password\n }).done(data => {\n $('#testPHT-result').html(data);\n $('#testPHT').prop('disabled', false);\n });\n },\n\n testPMS() {\n const plex = {};\n plex.server = {};\n const plexHostsInput = $('#plex_server_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.server.host = plexHosts.join(',');\n plex.server.username = $.trim($('#plex_server_username').val());\n plex.server.password = $.trim($('#plex_server_password').val());\n plex.server.token = $.trim($('#plex_server_token').val());\n\n if (!plex.server.host) {\n $('#testPMS-result').html('Please fill out the necessary fields above.');\n $('#plex_server_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_server_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPMS-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPMS', {\n host: plex.server.host,\n username: plex.server.username,\n password: plex.server.password,\n plex_server_token: plex.server.token // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testPMS-result').html(data);\n $('#testPMS').prop('disabled', false);\n });\n },\n\n testEMBY() {\n const emby = {};\n emby.host = $('#emby_host').val();\n emby.apikey = $('#emby_apikey').val();\n\n if (!emby.host || !emby.apikey) {\n $('#testEMBY-result').html('Please fill out the necessary fields above.');\n $('#emby_host').addRemoveWarningClass(emby.host);\n $('#emby_apikey').addRemoveWarningClass(emby.apikey);\n return;\n }\n\n $('#emby_host,#emby_apikey').children('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testEMBY-result').html(MEDUSA.config.layout.loading);\n $.get('home/testEMBY', {\n host: emby.host,\n emby_apikey: emby.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testEMBY-result').html(data);\n $('#testEMBY').prop('disabled', false);\n });\n },\n\n testBoxcar2() {\n const boxcar2 = {};\n boxcar2.accesstoken = $.trim($('#boxcar2_accesstoken').val());\n\n if (!boxcar2.accesstoken) {\n $('#testBoxcar2-result').html('Please fill out the necessary fields above.');\n $('#boxcar2_accesstoken').addClass('warning');\n return;\n }\n\n $('#boxcar2_accesstoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testBoxcar2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testBoxcar2', {\n accesstoken: boxcar2.accesstoken\n }).done(data => {\n $('#testBoxcar2-result').html(data);\n $('#testBoxcar2').prop('disabled', false);\n });\n },\n\n testPushover() {\n const pushover = {};\n pushover.userkey = $('#pushover_userkey').val();\n pushover.apikey = $('#pushover_apikey').val();\n\n if (!pushover.userkey || !pushover.apikey) {\n $('#testPushover-result').html('Please fill out the necessary fields above.');\n $('#pushover_userkey').addRemoveWarningClass(pushover.userkey);\n $('#pushover_apikey').addRemoveWarningClass(pushover.apikey);\n return;\n }\n\n $('#pushover_userkey,#pushover_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushover-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushover', {\n userKey: pushover.userkey,\n apiKey: pushover.apikey\n }).done(data => {\n $('#testPushover-result').html(data);\n $('#testPushover').prop('disabled', false);\n });\n },\n\n testLibnotify() {\n $('#testLibnotify-result').html(MEDUSA.config.layout.loading);\n $.get('home/testLibnotify', data => {\n $('#testLibnotify-result').html(data);\n });\n },\n\n settingsNMJ() {\n const nmj = {};\n nmj.host = $('#nmj_host').val();\n\n if (nmj.host) {\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/settingsNMJ', {\n host: nmj.host\n }, data => {\n if (data === null) {\n $('#nmj_database').removeAttr('readonly');\n $('#nmj_mount').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJ-result').html(JSONData.message);\n $('#nmj_database').val(JSONData.database);\n $('#nmj_mount').val(JSONData.mount);\n\n if (JSONData.database) {\n $('#nmj_database').prop('readonly', true);\n } else {\n $('#nmj_database').removeAttr('readonly');\n }\n\n if (JSONData.mount) {\n $('#nmj_mount').prop('readonly', true);\n } else {\n $('#nmj_mount').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmj_host').focus();\n }\n },\n\n testNMJ() {\n const nmj = {};\n nmj.host = $.trim($('#nmj_host').val());\n nmj.database = $('#nmj_database').val();\n nmj.mount = $('#nmj_mount').val();\n\n if (nmj.host) {\n $('#nmj_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJ', {\n host: nmj.host,\n database: nmj.database,\n mount: nmj.mount\n }).done(data => {\n $('#testNMJ-result').html(data);\n $('#testNMJ').prop('disabled', false);\n });\n } else {\n $('#testNMJ-result').html('Please fill out the necessary fields above.');\n $('#nmj_host').addClass('warning');\n }\n },\n\n settingsNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $('#nmjv2_host').val();\n\n if (nmjv2.host) {\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n nmjv2.dbloc = '';\n const radios = document.getElementsByName('nmjv2_dbloc');\n\n for (let i = 0, len = radios.length; i < len; i++) {\n if (radios[i].checked) {\n nmjv2.dbloc = radios[i].value;\n break;\n }\n }\n\n nmjv2.dbinstance = $('#NMJv2db_instance').val();\n $.get('home/settingsNMJv2', {\n host: nmjv2.host,\n dbloc: nmjv2.dbloc,\n instance: nmjv2.dbinstance\n }, data => {\n if (data === null) {\n $('#nmjv2_database').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJv2-result').html(JSONData.message);\n $('#nmjv2_database').val(JSONData.database);\n\n if (JSONData.database) {\n $('#nmjv2_database').prop('readonly', true);\n } else {\n $('#nmjv2_database').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmjv2_host').focus();\n }\n },\n\n testNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $.trim($('#nmjv2_host').val());\n\n if (nmjv2.host) {\n $('#nmjv2_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJv2', {\n host: nmjv2.host\n }).done(data => {\n $('#testNMJv2-result').html(data);\n $('#testNMJv2').prop('disabled', false);\n });\n } else {\n $('#testNMJv2-result').html('Please fill out the necessary fields above.');\n $('#nmjv2_host').addClass('warning');\n }\n },\n\n testFreeMobile() {\n const freemobile = {};\n freemobile.id = $.trim($('#freemobile_id').val());\n freemobile.apikey = $.trim($('#freemobile_apikey').val());\n\n if (!freemobile.id || !freemobile.apikey) {\n $('#testFreeMobile-result').html('Please fill out the necessary fields above.');\n\n if (freemobile.id) {\n $('#freemobile_id').removeClass('warning');\n } else {\n $('#freemobile_id').addClass('warning');\n }\n\n if (freemobile.apikey) {\n $('#freemobile_apikey').removeClass('warning');\n } else {\n $('#freemobile_apikey').addClass('warning');\n }\n\n return;\n }\n\n $('#freemobile_id,#freemobile_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testFreeMobile-result').html(MEDUSA.config.layout.loading);\n $.get('home/testFreeMobile', {\n freemobile_id: freemobile.id,\n // eslint-disable-line camelcase\n freemobile_apikey: freemobile.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testFreeMobile-result').html(data);\n $('#testFreeMobile').prop('disabled', false);\n });\n },\n\n testTelegram() {\n const telegram = {};\n telegram.id = $.trim($('#telegram_id').val());\n telegram.apikey = $.trim($('#telegram_apikey').val());\n\n if (!telegram.id || !telegram.apikey) {\n $('#testTelegram-result').html('Please fill out the necessary fields above.');\n $('#telegram_id').addRemoveWarningClass(telegram.id);\n $('#telegram_apikey').addRemoveWarningClass(telegram.apikey);\n return;\n }\n\n $('#telegram_id,#telegram_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTelegram-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTelegram', {\n telegram_id: telegram.id,\n // eslint-disable-line camelcase\n telegram_apikey: telegram.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTelegram-result').html(data);\n $('#testTelegram').prop('disabled', false);\n });\n },\n\n testDiscord() {\n const {\n notifiers\n } = this;\n\n if (!notifiers.discord.webhook) {\n $('#testDiscord-result').html('Please fill out the necessary fields above.');\n $('#discord_webhook').addRemoveWarningClass(notifiers.discord.webhook);\n return;\n }\n\n $('#discord_id,#discord_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testDiscord-result').html(MEDUSA.config.layout.loading);\n $.get('home/testDiscord', {\n discord_webhook: notifiers.discord.webhook,\n // eslint-disable-line camelcase\n discord_tts: notifiers.discord.tts // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testDiscord-result').html(data);\n $('#testDiscord').prop('disabled', false);\n });\n },\n\n testSlack() {\n const slack = {};\n slack.webhook = $.trim($('#slack_webhook').val());\n\n if (!slack.webhook) {\n $('#testSlack-result').html('Please fill out the necessary fields above.');\n $('#slack_webhook').addRemoveWarningClass(slack.webhook);\n return;\n }\n\n $('#slack_webhook').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testSlack-result').html(MEDUSA.config.layout.loading);\n $.get('home/testslack', {\n slack_webhook: slack.webhook // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testSlack-result').html(data);\n $('#testSlack').prop('disabled', false);\n });\n },\n\n TraktGetPin() {\n window.open($('#trakt_pin_url').val(), 'popUp', 'toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550');\n $('#trakt_pin').prop('disabled', false);\n },\n\n authTrakt() {\n const trakt = {};\n trakt.pin = $('#trakt_pin').val();\n\n if (trakt.pin.length !== 0) {\n $.get('home/getTraktToken', {\n trakt_pin: trakt.pin // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTrakt-result').html(data);\n $('#authTrakt').addClass('hide');\n $('#trakt_pin').prop('disabled', true);\n $('#trakt_pin').val('');\n $('#TraktGetPin').removeClass('hide');\n });\n }\n },\n\n testTrakt() {\n const trakt = {};\n trakt.username = $.trim($('#trakt_username').val());\n trakt.trendingBlacklist = $.trim($('#trakt_blacklist_name').val());\n\n if (!trakt.username) {\n $('#testTrakt-result').html('Please fill out the necessary fields above.');\n $('#trakt_username').addRemoveWarningClass(trakt.username);\n return;\n }\n\n if (/\\s/g.test(trakt.trendingBlacklist)) {\n $('#testTrakt-result').html('Check blacklist name; the value needs to be a trakt slug');\n $('#trakt_blacklist_name').addClass('warning');\n return;\n }\n\n $('#trakt_username').removeClass('warning');\n $('#trakt_blacklist_name').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTrakt', {\n username: trakt.username,\n blacklist_name: trakt.trendingBlacklist // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTrakt-result').html(data);\n $('#testTrakt').prop('disabled', false);\n });\n },\n\n traktForceSync() {\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.getJSON('home/forceTraktSync', data => {\n $('#testTrakt-result').html(data.result);\n });\n },\n\n testEmail() {\n let to = '';\n const status = $('#testEmail-result');\n status.html(MEDUSA.config.layout.loading);\n let host = $('#email_host').val();\n host = host.length > 0 ? host : null;\n let port = $('#email_port').val();\n port = port.length > 0 ? port : null;\n const tls = $('#email_tls').find('input').is(':checked') ? 1 : 0;\n let from = $('#email_from').val();\n from = from.length > 0 ? from : 'root@localhost';\n const user = $('#email_username').val().trim();\n const pwd = $('#email_password').val();\n let err = '';\n\n if (host === null) {\n err += '
  • You must specify an SMTP hostname!
  • ';\n }\n\n if (port === null) {\n err += '
  • You must specify an SMTP port!
  • ';\n } else if (port.match(/^\\d+$/) === null || Number.parseInt(port, 10) > 65535) {\n err += '
  • SMTP port must be between 0 and 65535!
  • ';\n }\n\n if (err.length > 0) {\n err = '
      ' + err + '
    ';\n status.html(err);\n } else {\n to = prompt('Enter an email address to send the test to:', null); // eslint-disable-line no-alert\n\n if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {\n status.html('

    You must provide a recipient email address!

    ');\n } else {\n $.get('home/testEmail', {\n host,\n port,\n smtp_from: from,\n // eslint-disable-line camelcase\n use_tls: tls,\n // eslint-disable-line camelcase\n user,\n pwd,\n to\n }, msg => {\n $('#testEmail-result').html(msg);\n });\n }\n }\n },\n\n testPushalot() {\n const pushalot = {};\n pushalot.authToken = $.trim($('#pushalot_authorizationtoken').val());\n\n if (!pushalot.authToken) {\n $('#testPushalot-result').html('Please fill out the necessary fields above.');\n $('#pushalot_authorizationtoken').addClass('warning');\n return;\n }\n\n $('#pushalot_authorizationtoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushalot-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushalot', {\n authorizationToken: pushalot.authToken\n }).done(data => {\n $('#testPushalot-result').html(data);\n $('#testPushalot').prop('disabled', false);\n });\n }\n\n }\n});\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-1%5B0%5D.rules%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); +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 _api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api.js */ \"./src/api.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.mjs\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./src/components/helpers/index.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n name: 'config-notifications',\n components: {\n AppLink: _helpers__WEBPACK_IMPORTED_MODULE_1__.AppLink,\n ConfigTemplate: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTemplate,\n ConfigTextbox: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextbox,\n ConfigTextboxNumber: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextboxNumber,\n ConfigToggleSlider: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigToggleSlider,\n SelectList: _helpers__WEBPACK_IMPORTED_MODULE_1__.SelectList,\n ShowSelector: _helpers__WEBPACK_IMPORTED_MODULE_1__.ShowSelector\n },\n\n data() {\n return {\n prowlSelectedShow: null,\n prowlSelectedShowApiKeys: [],\n prowlPriorityOptions: [{\n text: 'Very Low',\n value: -2\n }, {\n text: 'Moderate',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverPriorityOptions: [{\n text: 'Lowest',\n value: -2\n }, {\n text: 'Low',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverSoundOptions: [{\n text: 'Default',\n value: 'default'\n }, {\n text: 'Pushover',\n value: 'pushover'\n }, {\n text: 'Bike',\n value: 'bike'\n }, {\n text: 'Bugle',\n value: 'bugle'\n }, {\n text: 'Cash Register',\n value: 'cashregister'\n }, {\n text: 'classical',\n value: 'classical'\n }, {\n text: 'Cosmic',\n value: 'cosmic'\n }, {\n text: 'Falling',\n value: 'falling'\n }, {\n text: 'Gamelan',\n value: 'gamelan'\n }, {\n text: 'Incoming',\n value: 'incoming'\n }, {\n text: 'Intermission',\n value: 'intermission'\n }, {\n text: 'Magic',\n value: 'magic'\n }, {\n text: 'Mechanical',\n value: 'mechanical'\n }, {\n text: 'Piano Bar',\n value: 'pianobar'\n }, {\n text: 'Siren',\n value: 'siren'\n }, {\n text: 'Space Alarm',\n value: 'spacealarm'\n }, {\n text: 'Tug Boat',\n value: 'tugboat'\n }, {\n text: 'Alien Alarm (long)',\n value: 'alien'\n }, {\n text: 'Climb (long)',\n value: 'climb'\n }, {\n text: 'Persistent (long)',\n value: 'persistant'\n }, {\n text: 'Pushover Echo (long)',\n value: 'echo'\n }, {\n text: 'Up Down (long)',\n value: 'updown'\n }, {\n text: 'None (silent)',\n value: 'none'\n }],\n pushbulletDeviceOptions: [{\n text: 'All devices',\n value: ''\n }],\n traktRequestSend: false,\n traktRequestAuthenticated: false,\n traktUserCode: '',\n traktRequestMessage: '',\n traktMethodOptions: [{\n text: 'Skip all',\n value: 0\n }, {\n text: 'Download pilot only',\n value: 1\n }, {\n text: 'Get whole show',\n value: 2\n }],\n pushbulletTestInfo: 'Click below to test.',\n joinTestInfo: 'Click below to test.',\n twitterTestInfo: 'Click below to test.',\n twitterKey: '',\n emailSelectedShow: null,\n emailSelectedShowAdresses: [],\n saving: false\n };\n },\n\n computed: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapState)({\n config: state => state.config.general,\n indexers: state => state.config.indexers,\n notifiers: state => state.config.notifiers\n }),\n\n traktIndexersOptions() {\n const {\n indexers\n } = this;\n const {\n traktIndexers\n } = indexers.main;\n const validTraktIndexer = Object.keys(indexers.indexers).filter(k => traktIndexers[k]);\n return validTraktIndexer.map(indexer => {\n return {\n text: indexer,\n value: indexers.indexers[indexer].id\n };\n });\n }\n\n },\n\n beforeMount() {\n // Wait for the next tick, so the component is rendered\n this.$nextTick(() => {\n $('#config-components').tabs();\n });\n },\n\n mounted() {\n // TODO: vueify this.\n $('#trakt_pin').on('keyup change', () => {\n if ($('#trakt_pin').val().length === 0) {\n $('#TraktGetPin').removeClass('hide');\n $('#authTrakt').addClass('hide');\n } else {\n $('#TraktGetPin').addClass('hide');\n $('#authTrakt').removeClass('hide');\n }\n });\n },\n\n methods: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapActions)(['getShows', 'setConfig']),\n\n onChangeProwlApi(items) {\n this.notifiers.prowl.api = items.map(item => item.value);\n },\n\n savePerShowNotifyList(listType, values) {\n const {\n emailSelectedShow,\n prowlSelectedShow\n } = this;\n const form = new FormData();\n\n if (listType === 'prowl') {\n form.set('show', prowlSelectedShow);\n form.set('prowlAPIs', values.map(apiKey => apiKey.value));\n } else {\n form.set('show', emailSelectedShow);\n form.set('emails', values.map(apiKey => apiKey.value));\n } // Save the list\n\n\n _api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute.post('home/saveShowNotifyList', form);\n },\n\n async prowlUpdateApiKeys(selectedShow) {\n this.prowlSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].prowl_notify_list ? response.data[selectedShow].prowl_notify_list.split(',') : [];\n this.prowlSelectedShowApiKeys = selectedShow ? list : [];\n }\n },\n\n async emailUpdateShowEmail(selectedShow) {\n this.emailSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].list ? response.data[selectedShow].list.split(',') : [];\n this.emailSelectedShowAdresses = selectedShow ? list : [];\n }\n },\n\n emailUpdateAddressList(items) {\n this.notifiers.email.addressList = items.map(x => x.value);\n },\n\n async getPushbulletDeviceOptions() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/getPushbulletDevices', {\n params: {\n api: pushbulletApiKey\n }\n });\n const options = [];\n const {\n data\n } = response;\n\n if (!data) {\n return false;\n }\n\n options.push({\n text: 'All devices',\n value: ''\n });\n\n for (const device of data.devices) {\n if (device.active === true) {\n options.push({\n text: device.nickname,\n value: device.iden\n });\n }\n }\n\n this.pushbulletDeviceOptions = options;\n this.pushbulletTestInfo = 'Device list updated. Please choose a device to push to.';\n },\n\n async testPushbulletApi() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testPushbullet', {\n params: {\n api: pushbulletApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.pushbulletTestInfo = data;\n }\n },\n\n async testJoinApi() {\n const {\n api: joinApiKey\n } = this.notifiers.join;\n\n if (!joinApiKey) {\n this.joinTestInfo = 'You didn\\'t supply a Join api key';\n $('#join_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testJoin', {\n params: {\n api: joinApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.joinTestInfo = data;\n }\n },\n\n async twitterStep1() {\n this.twitterTestInfo = MEDUSA.config.layout.loading;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep1');\n const {\n data\n } = response;\n window.open(data);\n this.twitterTestInfo = 'Step1: Confirm Authorization';\n },\n\n async twitterStep2() {\n const twitter = {};\n const {\n twitterKey\n } = this;\n twitter.key = twitterKey;\n\n if (twitter.key) {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep2', {\n params: {\n key: twitter.key\n }\n });\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } else {\n this.twitterTestInfo = 'Please fill out the necessary fields above.';\n }\n },\n\n async twitterTest() {\n try {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testTwitter');\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } catch (error) {\n this.twitterTestInfo = 'Error while trying to request for a test on the twitter api.';\n }\n },\n\n async save() {\n const {\n notifiers,\n setConfig\n } = this; // Disable the save button until we're done.\n\n this.saving = true;\n const section = 'main';\n\n try {\n await setConfig({\n section,\n config: {\n notifiers\n }\n });\n this.$snotify.success('Saved Notifiers config', 'Saved', {\n timeout: 5000\n });\n } catch (error) {\n this.$snotify.error('Error while trying to save notifiers config', 'Error');\n } finally {\n this.saving = false;\n }\n },\n\n testGrowl() {\n const growl = {};\n growl.host = $.trim($('#growl_host').val());\n growl.password = $.trim($('#growl_password').val());\n\n if (!growl.host) {\n $('#testGrowl-result').html('Please fill out the necessary fields above.');\n $('#growl_host').addClass('warning');\n return;\n }\n\n $('#growl_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testGrowl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testGrowl', {\n host: growl.host,\n password: growl.password\n }).done(data => {\n $('#testGrowl-result').html(data);\n $('#testGrowl').prop('disabled', false);\n });\n },\n\n testProwl() {\n const prowl = {};\n prowl.api = $.trim($('#prowl_api').find('input').val());\n prowl.priority = $('#prowl_priority').find('input').val();\n\n if (!prowl.api) {\n $('#testProwl-result').html('Please fill out the necessary fields above.');\n $('#prowl_api').find('input').addClass('warning');\n return;\n }\n\n $('#prowl_api').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testProwl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testProwl', {\n prowl_api: prowl.api,\n // eslint-disable-line camelcase\n prowl_priority: prowl.priority // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testProwl-result').html(data);\n $('#testProwl').prop('disabled', false);\n });\n },\n\n testKODI() {\n const kodi = {};\n const kodiHostInput = $('#kodi_host').find('input');\n const kodiHosts = kodiHostInput.toArray().map(value => value.value).filter(item => item !== '');\n kodi.host = kodiHosts.join(',');\n kodi.username = $.trim($('#kodi_username').val());\n kodi.password = $.trim($('#kodi_password').val());\n\n if (!kodi.host) {\n $('#testKODI-result').html('Please fill out the necessary fields above.');\n $('#kodi_host').find('input').addClass('warning');\n return;\n }\n\n $('#kodi_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testKODI-result').html(MEDUSA.config.layout.loading);\n $.get('home/testKODI', {\n host: kodi.host,\n username: kodi.username,\n password: kodi.password\n }).done(data => {\n $('#testKODI-result').html(data);\n $('#testKODI').prop('disabled', false);\n });\n },\n\n testPHT() {\n const plex = {};\n plex.client = {};\n const plexHostsInput = $('#plex_client_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.client.host = plexHosts.join(',');\n plex.client.username = $.trim($('#plex_client_username').val());\n plex.client.password = $.trim($('#plex_client_password').val());\n\n if (!plex.client.host) {\n $('#testPHT-result').html('Please fill out the necessary fields above.');\n $('#plex_client_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_client_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPHT-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPHT', {\n host: plex.client.host,\n username: plex.client.username,\n password: plex.client.password\n }).done(data => {\n $('#testPHT-result').html(data);\n $('#testPHT').prop('disabled', false);\n });\n },\n\n testPMS() {\n const plex = {};\n plex.server = {};\n const plexHostsInput = $('#plex_server_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.server.host = plexHosts.join(',');\n plex.server.username = $.trim($('#plex_server_username').val());\n plex.server.password = $.trim($('#plex_server_password').val());\n plex.server.token = $.trim($('#plex_server_token').val());\n\n if (!plex.server.host) {\n $('#testPMS-result').html('Please fill out the necessary fields above.');\n $('#plex_server_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_server_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPMS-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPMS', {\n host: plex.server.host,\n username: plex.server.username,\n password: plex.server.password,\n plex_server_token: plex.server.token // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testPMS-result').html(data);\n $('#testPMS').prop('disabled', false);\n });\n },\n\n testEMBY() {\n const emby = {};\n emby.host = $('#emby_host').val();\n emby.apikey = $('#emby_apikey').val();\n\n if (!emby.host || !emby.apikey) {\n $('#testEMBY-result').html('Please fill out the necessary fields above.');\n $('#emby_host').addRemoveWarningClass(emby.host);\n $('#emby_apikey').addRemoveWarningClass(emby.apikey);\n return;\n }\n\n $('#emby_host,#emby_apikey').children('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testEMBY-result').html(MEDUSA.config.layout.loading);\n $.get('home/testEMBY', {\n host: emby.host,\n emby_apikey: emby.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testEMBY-result').html(data);\n $('#testEMBY').prop('disabled', false);\n });\n },\n\n testBoxcar2() {\n const boxcar2 = {};\n boxcar2.accesstoken = $.trim($('#boxcar2_accesstoken').val());\n\n if (!boxcar2.accesstoken) {\n $('#testBoxcar2-result').html('Please fill out the necessary fields above.');\n $('#boxcar2_accesstoken').addClass('warning');\n return;\n }\n\n $('#boxcar2_accesstoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testBoxcar2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testBoxcar2', {\n accesstoken: boxcar2.accesstoken\n }).done(data => {\n $('#testBoxcar2-result').html(data);\n $('#testBoxcar2').prop('disabled', false);\n });\n },\n\n testPushover() {\n const pushover = {};\n pushover.userkey = $('#pushover_userkey').val();\n pushover.apikey = $('#pushover_apikey').val();\n\n if (!pushover.userkey || !pushover.apikey) {\n $('#testPushover-result').html('Please fill out the necessary fields above.');\n $('#pushover_userkey').addRemoveWarningClass(pushover.userkey);\n $('#pushover_apikey').addRemoveWarningClass(pushover.apikey);\n return;\n }\n\n $('#pushover_userkey,#pushover_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushover-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushover', {\n userKey: pushover.userkey,\n apiKey: pushover.apikey\n }).done(data => {\n $('#testPushover-result').html(data);\n $('#testPushover').prop('disabled', false);\n });\n },\n\n testLibnotify() {\n $('#testLibnotify-result').html(MEDUSA.config.layout.loading);\n $.get('home/testLibnotify', data => {\n $('#testLibnotify-result').html(data);\n });\n },\n\n settingsNMJ() {\n const nmj = {};\n nmj.host = $('#nmj_host').val();\n\n if (nmj.host) {\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/settingsNMJ', {\n host: nmj.host\n }, data => {\n if (data === null) {\n $('#nmj_database').removeAttr('readonly');\n $('#nmj_mount').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJ-result').html(JSONData.message);\n $('#nmj_database').val(JSONData.database);\n $('#nmj_mount').val(JSONData.mount);\n\n if (JSONData.database) {\n $('#nmj_database').prop('readonly', true);\n } else {\n $('#nmj_database').removeAttr('readonly');\n }\n\n if (JSONData.mount) {\n $('#nmj_mount').prop('readonly', true);\n } else {\n $('#nmj_mount').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmj_host').focus();\n }\n },\n\n testNMJ() {\n const nmj = {};\n nmj.host = $.trim($('#nmj_host').val());\n nmj.database = $('#nmj_database').val();\n nmj.mount = $('#nmj_mount').val();\n\n if (nmj.host) {\n $('#nmj_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJ', {\n host: nmj.host,\n database: nmj.database,\n mount: nmj.mount\n }).done(data => {\n $('#testNMJ-result').html(data);\n $('#testNMJ').prop('disabled', false);\n });\n } else {\n $('#testNMJ-result').html('Please fill out the necessary fields above.');\n $('#nmj_host').addClass('warning');\n }\n },\n\n settingsNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $('#nmjv2_host').val();\n\n if (nmjv2.host) {\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n nmjv2.dbloc = '';\n const radios = document.getElementsByName('nmjv2_dbloc');\n\n for (let i = 0, len = radios.length; i < len; i++) {\n if (radios[i].checked) {\n nmjv2.dbloc = radios[i].value;\n break;\n }\n }\n\n nmjv2.dbinstance = $('#NMJv2db_instance').val();\n $.get('home/settingsNMJv2', {\n host: nmjv2.host,\n dbloc: nmjv2.dbloc,\n instance: nmjv2.dbinstance\n }, data => {\n if (data === null) {\n $('#nmjv2_database').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJv2-result').html(JSONData.message);\n $('#nmjv2_database').val(JSONData.database);\n\n if (JSONData.database) {\n $('#nmjv2_database').prop('readonly', true);\n } else {\n $('#nmjv2_database').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmjv2_host').focus();\n }\n },\n\n testNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $.trim($('#nmjv2_host').val());\n\n if (nmjv2.host) {\n $('#nmjv2_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJv2', {\n host: nmjv2.host\n }).done(data => {\n $('#testNMJv2-result').html(data);\n $('#testNMJv2').prop('disabled', false);\n });\n } else {\n $('#testNMJv2-result').html('Please fill out the necessary fields above.');\n $('#nmjv2_host').addClass('warning');\n }\n },\n\n testFreeMobile() {\n const freemobile = {};\n freemobile.id = $.trim($('#freemobile_id').val());\n freemobile.apikey = $.trim($('#freemobile_apikey').val());\n\n if (!freemobile.id || !freemobile.apikey) {\n $('#testFreeMobile-result').html('Please fill out the necessary fields above.');\n\n if (freemobile.id) {\n $('#freemobile_id').removeClass('warning');\n } else {\n $('#freemobile_id').addClass('warning');\n }\n\n if (freemobile.apikey) {\n $('#freemobile_apikey').removeClass('warning');\n } else {\n $('#freemobile_apikey').addClass('warning');\n }\n\n return;\n }\n\n $('#freemobile_id,#freemobile_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testFreeMobile-result').html(MEDUSA.config.layout.loading);\n $.get('home/testFreeMobile', {\n freemobile_id: freemobile.id,\n // eslint-disable-line camelcase\n freemobile_apikey: freemobile.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testFreeMobile-result').html(data);\n $('#testFreeMobile').prop('disabled', false);\n });\n },\n\n testTelegram() {\n const telegram = {};\n telegram.id = $.trim($('#telegram_id').val());\n telegram.apikey = $.trim($('#telegram_apikey').val());\n\n if (!telegram.id || !telegram.apikey) {\n $('#testTelegram-result').html('Please fill out the necessary fields above.');\n $('#telegram_id').addRemoveWarningClass(telegram.id);\n $('#telegram_apikey').addRemoveWarningClass(telegram.apikey);\n return;\n }\n\n $('#telegram_id,#telegram_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTelegram-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTelegram', {\n telegram_id: telegram.id,\n // eslint-disable-line camelcase\n telegram_apikey: telegram.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTelegram-result').html(data);\n $('#testTelegram').prop('disabled', false);\n });\n },\n\n testDiscord() {\n const {\n notifiers\n } = this;\n\n if (!notifiers.discord.webhook) {\n $('#testDiscord-result').html('Please fill out the necessary fields above.');\n $('#discord_webhook').addRemoveWarningClass(notifiers.discord.webhook);\n return;\n }\n\n $('#discord_id,#discord_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testDiscord-result').html(MEDUSA.config.layout.loading);\n $.get('home/testDiscord', {\n discord_webhook: notifiers.discord.webhook,\n // eslint-disable-line camelcase\n discord_tts: notifiers.discord.tts // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testDiscord-result').html(data);\n $('#testDiscord').prop('disabled', false);\n });\n },\n\n testSlack() {\n const slack = {};\n slack.webhook = $.trim($('#slack_webhook').val());\n\n if (!slack.webhook) {\n $('#testSlack-result').html('Please fill out the necessary fields above.');\n $('#slack_webhook').addRemoveWarningClass(slack.webhook);\n return;\n }\n\n $('#slack_webhook').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testSlack-result').html(MEDUSA.config.layout.loading);\n $.get('home/testslack', {\n slack_webhook: slack.webhook // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testSlack-result').html(data);\n $('#testSlack').prop('disabled', false);\n });\n },\n\n async TraktRequestDeviceCode() {\n this.traktUserCode = '';\n this.traktRequestAuthenticated = false;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/requestTraktDeviceCodeOauth');\n\n if (response.data) {\n this.traktVerificationUrl = response.data.verification_url;\n window.open(response.data.verification_url, 'popUp', 'toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550');\n this.traktRequestSend = true;\n this.traktUserCode = response.data.user_code;\n this.checkTraktAuthenticated();\n }\n },\n\n checkTraktAuthenticated() {\n let counter = 0;\n const i = setInterval(() => {\n (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/checkTrakTokenOauth').then(response => {\n if (response.data) {\n this.traktRequestMessage = response.data.result;\n\n if (!response.data.error) {\n clearInterval(i);\n this.traktRequestAuthenticated = true;\n this.traktUserCode = '';\n }\n }\n });\n counter++;\n\n if (counter === 12) {\n clearInterval(i);\n this.traktRequestAuthenticated = false;\n this.traktUserCode = '';\n }\n }, 5000);\n },\n\n testTrakt() {\n const trakt = {};\n trakt.trendingBlacklist = $.trim($('#trakt_blacklist_name').val());\n\n if (/\\s/g.test(trakt.trendingBlacklist)) {\n $('#testTrakt-result').html('Check blacklist name; the value needs to be a trakt slug');\n $('#trakt_blacklist_name').addClass('warning');\n return;\n }\n\n $('#trakt_blacklist_name').removeClass('warning');\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)(`home/testTrakt?blacklist_name=${trakt.trendingBlacklist}`).then(result => {\n $('#testTrakt-result').html(result.data);\n $('#testTrakt').prop('disabled', false);\n });\n },\n\n traktForceSync() {\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.getJSON('home/forceTraktSync', data => {\n $('#testTrakt-result').html(data.result);\n });\n },\n\n testEmail() {\n let to = '';\n const status = $('#testEmail-result');\n status.html(MEDUSA.config.layout.loading);\n let host = $('#email_host').val();\n host = host.length > 0 ? host : null;\n let port = $('#email_port').val();\n port = port.length > 0 ? port : null;\n const tls = $('#email_tls').find('input').is(':checked') ? 1 : 0;\n let from = $('#email_from').val();\n from = from.length > 0 ? from : 'root@localhost';\n const user = $('#email_username').val().trim();\n const pwd = $('#email_password').val();\n let err = '';\n\n if (host === null) {\n err += '
  • You must specify an SMTP hostname!
  • ';\n }\n\n if (port === null) {\n err += '
  • You must specify an SMTP port!
  • ';\n } else if (port.match(/^\\d+$/) === null || Number.parseInt(port, 10) > 65535) {\n err += '
  • SMTP port must be between 0 and 65535!
  • ';\n }\n\n if (err.length > 0) {\n err = '
      ' + err + '
    ';\n status.html(err);\n } else {\n to = prompt('Enter an email address to send the test to:', null); // eslint-disable-line no-alert\n\n if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {\n status.html('

    You must provide a recipient email address!

    ');\n } else {\n $.get('home/testEmail', {\n host,\n port,\n smtp_from: from,\n // eslint-disable-line camelcase\n use_tls: tls,\n // eslint-disable-line camelcase\n user,\n pwd,\n to\n }, msg => {\n $('#testEmail-result').html(msg);\n });\n }\n }\n },\n\n testPushalot() {\n const pushalot = {};\n pushalot.authToken = $.trim($('#pushalot_authorizationtoken').val());\n\n if (!pushalot.authToken) {\n $('#testPushalot-result').html('Please fill out the necessary fields above.');\n $('#pushalot_authorizationtoken').addClass('warning');\n return;\n }\n\n $('#pushalot_authorizationtoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushalot-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushalot', {\n authorizationToken: pushalot.authToken\n }).done(data => {\n $('#testPushalot-result').html(data);\n $('#testPushalot').prop('disabled', false);\n });\n }\n\n }\n});\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-1%5B0%5D.rules%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }), @@ -4439,7 +4439,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 */ \"render\": () => /* binding */ render,\n/* harmony export */ \"staticRenderFns\": () => /* binding */ staticRenderFns\n/* harmony export */ });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"config-notifications\" } },\n [\n _c(\"vue-snotify\"),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"config\" } }, [\n _c(\"div\", { attrs: { id: \"config-content\" } }, [\n _c(\n \"form\",\n {\n attrs: { id: \"configForm\", method: \"post\" },\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.save()\n }\n }\n },\n [\n _c(\"div\", { attrs: { id: \"config-components\" } }, [\n _c(\"ul\", [\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#home-theater-nas\" } }, [\n _vm._v(\"Home Theater / NAS\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#devices\" } }, [\n _vm._v(\"Devices\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#social\" } }, [\n _vm._v(\"Social\")\n ])\n ],\n 1\n )\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"home-theater-nas\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-kodi\",\n attrs: { title: \"KODI\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://kodi.tv\" } },\n [_vm._v(\"KODI\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A free and open source cross-platform media center and home entertainment system software with a 10-foot user interface designed for the living-room TV.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_kodi\",\n explanations: [\"Send KODI commands?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.kodi, \"enabled\", $$v)\n },\n expression: \"notifiers.kodi.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.kodi.enabled,\n expression: \"notifiers.kodi.enabled\"\n }\n ],\n attrs: { id: \"content-use-kodi\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Always on\",\n id: \"kodi_always_on\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.alwaysOn,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"alwaysOn\",\n $$v\n )\n },\n expression: \"notifiers.kodi.alwaysOn\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"kodi_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"kodi_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"kodi_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.kodi.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.kodi.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update library\",\n id: \"kodi_update_library\",\n explanations: [\n \"update KODI library when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.library,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"library\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.library\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Full library update\",\n id: \"kodi_update_full\",\n explanations: [\n \"perform a full library update if update per-show fails?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.full,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"full\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.full\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Clean library\",\n id: \"kodi_clean_library\",\n explanations: [\n \"clean KODI library when replaces a already downloaded episode?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.cleanLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"cleanLibrary\",\n $$v\n )\n },\n expression: \"notifiers.kodi.cleanLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Only update first host\",\n id: \"kodi_update_onlyfirst\",\n explanations: [\n \"only send library updates/clean to the first active host?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.onlyFirst,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"onlyFirst\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.onlyFirst\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"col-sm-10 content\" },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"kodi_host\",\n id: \"kodi_host\",\n \"list-items\": _vm.notifiers.kodi.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.kodi.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"host running KODI (eg. 192.168.1.100:8080)\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"kodi_username\",\n explanations: [\n \"username for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.kodi.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"kodi_password\",\n explanations: [\n \"password for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.kodi.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testKODI-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test KODI\",\n id: \"testKODI\"\n },\n on: { click: _vm.testKODI }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plex\",\n attrs: { title: \"Plex Media Server\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Media Server\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Experience your media on a visually stunning, easy to use interface on your Mac connected to your TV. Your media library has never looked this good!\"\n )\n ]),\n _vm._v(\" \"),\n _vm.notifiers.plex.server.enabled\n ? _c(\"p\", { staticClass: \"plexinfo\" }, [\n _vm._v(\n \"For sending notifications to Plex Home Theater (PHT) clients, use the KODI notifier with port \"\n ),\n _c(\"b\", [_vm._v(\"3005\")]),\n _vm._v(\".\")\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_server\",\n explanations: [\"Send Plex server notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.server.enabled,\n expression: \"notifiers.plex.server.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-server\" }\n },\n [\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Plex Media Server Auth Token\",\n id: \"plex_server_token\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.token,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"token\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.token\"\n }\n },\n [\n _c(\"p\", [_vm._v(\"Auth Token used by plex\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\n \"span\",\n [\n _vm._v(\"See: \"),\n _c(\n \"app-link\",\n {\n staticClass: \"wiki\",\n attrs: {\n href:\n \"https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token\"\n }\n },\n [\n _c(\"strong\", [\n _vm._v(\n \"Finding your account token\"\n )\n ])\n ]\n )\n ],\n 1\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_server_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_server_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update Library\",\n id: \"plex_update_library\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.server.updateLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"updateLibrary\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.server.updateLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_server_host\",\n label: \"Plex Media Server IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_server_host\",\n id: \"plex_server_host\",\n \"list-items\":\n _vm.notifiers.plex.server.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.server.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Media Server\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.1:32400, 192.168.1.2:32400)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"plex_server_https\",\n explanations: [\n \"use https for plex media server requests?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.https,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"https\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.https\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPMS-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Media Server(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Media Server\",\n id: \"testPMS\"\n },\n on: { click: _vm.testPMS }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clear-left\" }, [\n _vm._v(\" \")\n ])\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plexth\",\n attrs: { title: \"Plex Media Client\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Home Theater\")]\n )\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_client\",\n explanations: [\n \"Send Plex Home Theater notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.client.enabled,\n expression: \"notifiers.plex.client.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"plex_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"plex_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"plex_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_client_host\",\n label: \"Plex Home Theater IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_client_host\",\n id: \"plex_client_host\",\n \"list-items\":\n _vm.notifiers.plex.client.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.client.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Home Theater\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.100:3000, 192.168.1.101:3000)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_client_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_client_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPHT-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Home Theater(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Home Theater\",\n id: \"testPHT\"\n },\n on: { click: _vm.testPHT }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _vm._m(1)\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-emby\",\n attrs: { title: \"Emby\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://emby.media\" } },\n [_vm._v(\"Emby\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A home media server built using other popular open source technologies.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_emby\",\n explanations: [\"Send update commands to Emby?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"enabled\", $$v)\n },\n expression: \"notifiers.emby.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.emby.enabled,\n expression: \"notifiers.emby.enabled\"\n }\n ],\n attrs: { id: \"content_use_emby\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Emby IP:Port\",\n id: \"emby_host\",\n explanations: [\n \"host running Emby (eg. 192.168.1.100:8096)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"host\", $$v)\n },\n expression: \"notifiers.emby.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: { label: \"Api Key\", id: \"emby_apikey\" },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.apiKey,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"apiKey\", $$v)\n },\n expression: \"notifiers.emby.apiKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEMBY-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Emby\",\n id: \"testEMBY\"\n },\n on: { click: _vm.testEMBY }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJ\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmj\",\n explanations: [\"Send update commands to NMJ?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"enabled\", $$v)\n },\n expression: \"notifiers.nmj.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmj.enabled,\n expression: \"notifiers.nmj.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmj\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmj_host\",\n explanations: [\n \"IP address of Popcorn 200-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"host\", $$v)\n },\n expression: \"notifiers.nmj.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"settingsNMJ\",\n label: \"Get settings\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Get Settings\",\n id: \"settingsNMJ\"\n },\n on: { click: _vm.settingsNMJ }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on and NMJ running.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ database\",\n id: \"nmj_database\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.database,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"database\", $$v)\n },\n expression: \"notifiers.nmj.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ mount\",\n id: \"nmj_mount\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.mount,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"mount\", $$v)\n },\n expression: \"notifiers.nmj.mount\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJ-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJ\",\n id: \"testNMJ\"\n },\n on: { click: _vm.testNMJ }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox v2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJv2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJv2, is the official media jukebox interface made available for the Popcorn Hour 300 & 400-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmjv2\",\n explanations: [\n \"Send popcorn hour (nmjv2) notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"enabled\", $$v)\n },\n expression: \"notifiers.nmjv2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmjv2.enabled,\n expression: \"notifiers.nmjv2.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmjv2\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmjv2_host\",\n explanations: [\n \"IP address of Popcorn 300/400-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"host\", $$v)\n },\n expression: \"notifiers.nmjv2.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_location\",\n label: \"Database location\"\n }\n },\n [\n _c(\n \"label\",\n {\n staticClass: \"space-right\",\n attrs: { for: \"NMJV2_DBLOC_A\" }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"local\",\n id: \"NMJV2_DBLOC_A\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Local Media\\n \"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"label\",\n { attrs: { for: \"NMJV2_DBLOC_B\" } },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"network\",\n id: \"NMJV2_DBLOC_B\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Network Media\\n \"\n )\n ]\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_instance\",\n label: \"Database instance\"\n }\n },\n [\n _c(\n \"select\",\n {\n staticClass: \"form-control input-sm\",\n attrs: { id: \"NMJv2db_instance\" }\n },\n [\n _c(\"option\", { attrs: { value: \"0\" } }, [\n _vm._v(\"#1 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"1\" } }, [\n _vm._v(\"#2 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"2\" } }, [\n _vm._v(\"#3 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"3\" } }, [\n _vm._v(\"#4 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"4\" } }, [\n _vm._v(\"#5 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"5\" } }, [\n _vm._v(\"#6 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"6\" } }, [\n _vm._v(\"#7 \")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"adjust this value if the wrong database is selected.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"get_nmjv2_find_database\",\n label: \"Find database\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Find Database\",\n id: \"settingsNMJv2\"\n },\n on: { click: _vm.settingsNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJv2 database\",\n id: \"nmjv2_database\",\n explanations: [\n \"automatically filled via the 'Find Database' buttons.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.database,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.nmjv2,\n \"database\",\n $$v\n )\n },\n expression: \"notifiers.nmjv2.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJv2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJv2\",\n id: \"testNMJv2\"\n },\n on: { click: _vm.testNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno1\",\n attrs: { title: \"Synology\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"The Synology DiskStation NAS.\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Indexer is the daemon running on the Synology NAS to build its media database.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"use_synoindex\",\n explanations: [\n \"Note: requires Medusa to be running on your Synology NAS.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synologyIndex.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synologyIndex,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.synologyIndex.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synologyIndex.enabled,\n expression: \"notifiers.synologyIndex.enabled\"\n }\n ],\n attrs: { id: \"content_use_synoindex\" }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ]\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno2\",\n attrs: { title: \"Synology Indexer\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology Notifier\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Notifier is the notification system of Synology DSM\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_synologynotifier\",\n explanations: [\n \"Send notifications to the Synology Notifier?\",\n \"Note: requires Medusa to be running on your Synology DSM.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.synology, \"enabled\", $$v)\n },\n expression: \"notifiers.synology.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synology.enabled,\n expression: \"notifiers.synology.enabled\"\n }\n ],\n attrs: { id: \"content-use-synology-notifier\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"synology_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"synology_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pytivo\",\n attrs: { title: \"pyTivo\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://pytivo.sourceforge.net/wiki/index.php/PyTivo\"\n }\n },\n [_vm._v(\"pyTivo\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pytivo\",\n explanations: [\"Send notifications to pyTivo?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"enabled\", $$v)\n },\n expression: \"notifiers.pyTivo.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pyTivo.enabled,\n expression: \"notifiers.pyTivo.enabled\"\n }\n ],\n attrs: { id: \"content-use-pytivo\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo IP:Port\",\n id: \"pytivo_host\",\n explanations: [\n \"host running pyTivo (eg. 192.168.1.1:9032)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"host\", $$v)\n },\n expression: \"notifiers.pyTivo.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo share name\",\n id: \"pytivo_name\",\n explanations: [\n \"(Messages & Settings > Account & System Information > System Information > DVR name)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.shareName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pyTivo,\n \"shareName\",\n $$v\n )\n },\n expression: \"notifiers.pyTivo.shareName\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Tivo name\",\n id: \"pytivo_tivo_name\",\n explanations: [\n \"value used in pyTivo Web Configuration to name the share.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"name\", $$v)\n },\n expression: \"notifiers.pyTivo.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"devices\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-growl\",\n attrs: { title: \"Growl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://growl.info/\" } },\n [_vm._v(\"Growl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A cross-platform unobtrusive global notification system.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_growl_client\",\n explanations: [\"Send Growl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"enabled\", $$v)\n },\n expression: \"notifiers.growl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.growl.enabled,\n expression: \"notifiers.growl.enabled\"\n }\n ],\n attrs: { id: \"content-use-growl-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"growl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"growl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"growl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.growl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.growl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Growl IP:Port\",\n id: \"growl_host\",\n explanations: [\n \"host running Growl (eg. 192.168.1.100:23053)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"host\", $$v)\n },\n expression: \"notifiers.growl.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"growl_password\",\n explanations: [\n \"may leave blank if Medusa is on the same host.\",\n \"otherwise Growl requires a password to be used.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.growl.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testGrowl-result\" }\n },\n [\n _vm._v(\n \"Click below to register and test Growl, this is required for Growl notifications to work.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Register Growl\",\n id: \"testGrowl\"\n },\n on: { click: _vm.testGrowl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-prowl\",\n attrs: { title: \"Prowl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://www.prowlapp.com/\" } },\n [_vm._v(\"Prowl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"A Growl client for iOS.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_prowl\",\n explanations: [\"Send Prowl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.prowl, \"enabled\", $$v)\n },\n expression: \"notifiers.prowl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.prowl.enabled,\n expression: \"notifiers.prowl.enabled\"\n }\n ],\n attrs: { id: \"content-use-prowl\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"prowl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"prowl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"prowl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.prowl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.prowl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Prowl Message Title\",\n id: \"prowl_message_title\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.messageTitle,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"messageTitle\",\n $$v\n )\n },\n expression: \"notifiers.prowl.messageTitle\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_api\",\n label: \"Api\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl_api\",\n id: \"prowl_api\",\n \"csv-enabled\": \"\",\n \"list-items\": _vm.notifiers.prowl.api\n },\n on: { change: _vm.onChangeProwlApi }\n }),\n _vm._v(\" \"),\n _c(\n \"span\",\n [\n _vm._v(\n \"Prowl API(s) listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\n \" shows.\\n Your Prowl API key is available at:\\n \"\n ),\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://www.prowlapp.com/api_settings.php\"\n }\n },\n [\n _vm._v(\n \"\\n https://www.prowlapp.com/api_settings.php\"\n )\n ]\n ),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_show_notification_list\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.prowlUpdateApiKeys($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl-show-list\",\n id: \"prowl-show-list\",\n \"list-items\":\n _vm.prowlSelectedShowApiKeys\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"prowl\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Configure per-show notifications here by entering Prowl API key(s), after selecting a show in the drop-down box.\\n Be sure to activate the 'Save for this show' button below after each entry.\\n \"\n ),\n _c(\"span\", [\n _vm._v(\n \"The values are automatically saved when adding the api key.\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_priority\",\n label: \"Prowl priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.prowl.priority,\n expression: \"notifiers.prowl.priority\"\n }\n ],\n staticClass: \"form-control input-sm\",\n attrs: {\n id: \"prowl_priority\",\n name: \"prowl_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.prowl,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.prowlPriorityOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Prowl messages from Medusa.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testProwl-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Prowl\",\n id: \"testProwl\"\n },\n on: { click: _vm.testProwl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-libnotify\",\n attrs: { title: \"Libnotify\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://library.gnome.org/devel/libnotify/\"\n }\n },\n [_vm._v(\"Libnotify\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"p\",\n [\n _vm._v(\n \"The standard desktop notification API for Linux/*nix systems. This notifier will only function if the pynotify module is installed (Ubuntu/Debian package \"\n ),\n _c(\n \"app-link\",\n { attrs: { href: \"apt:python-notify\" } },\n [_vm._v(\"python-notify\")]\n ),\n _vm._v(\").\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_libnotify_client\",\n explanations: [\"Send Libnotify notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.libnotify.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.libnotify.enabled,\n expression: \"notifiers.libnotify.enabled\"\n }\n ],\n attrs: { id: \"content-use-libnotify\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"libnotify_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"libnotify_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"libnotify_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testLibnotify-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Libnotify\",\n id: \"testLibnotify\"\n },\n on: { click: _vm.testLibnotify }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushover\",\n attrs: { title: \"Pushover\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushover.net/\" } },\n [_vm._v(\"Pushover\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushover makes it easy to send real-time notifications to your Android and iOS devices.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushover_client\",\n explanations: [\"Send Pushover notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushover, \"enabled\", $$v)\n },\n expression: \"notifiers.pushover.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushover.enabled,\n expression: \"notifiers.pushover.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushover\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushover_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushover_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushover_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushover User Key\",\n id: \"pushover_userkey\",\n explanations: [\n \"User Key of your Pushover account\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.userKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"userKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.userKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Pushover API Key\",\n id: \"pushover_apikey\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.apiKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"apiKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.apiKey\"\n }\n },\n [\n _c(\n \"span\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://pushover.net/apps/build/\"\n }\n },\n [_c(\"b\", [_vm._v(\"Click here\")])]\n ),\n _vm._v(\" to create a Pushover API key\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_device\",\n label: \"Pushover Devices\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"pushover_device\",\n id: \"pushover_device\",\n \"list-items\":\n _vm.notifiers.pushover.device\n },\n on: {\n change: function($event) {\n _vm.notifiers.pushover.device = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"List of pushover devices you want to send notifications to\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_sound\",\n label: \"Pushover notification sound\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.pushover.sound,\n expression: \"notifiers.pushover.sound\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_sound\",\n name: \"pushover_sound\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"sound\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.pushoverSoundOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"Choose notification sound to use\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_priority\",\n label: \"Pushover notification priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushover.priority,\n expression:\n \"notifiers.pushover.priority\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_priority\",\n name: \"pushover_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushoverPriorityOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Pushover messages from Medusa\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushover-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushover\",\n id: \"testPushover\"\n },\n on: { click: _vm.testPushover }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-boxcar2\",\n attrs: { title: \"Boxcar 2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://new.boxcar.io/\" } },\n [_vm._v(\"Boxcar 2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Read your messages where and when you want them!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_boxcar2\",\n explanations: [\"Send boxcar2 notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.boxcar2, \"enabled\", $$v)\n },\n expression: \"notifiers.boxcar2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.boxcar2.enabled,\n expression: \"notifiers.boxcar2.enabled\"\n }\n ],\n attrs: { id: \"content-use-boxcar2-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"boxcar2_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"boxcar2_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"boxcar2_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.boxcar2\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Boxcar2 Access token\",\n id: \"boxcar2_accesstoken\",\n explanations: [\n \"access token for your Boxcar account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.accessToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"accessToken\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.accessToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testBoxcar2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Boxcar\",\n id: \"testBoxcar2\"\n },\n on: { click: _vm.testBoxcar2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushalot\",\n attrs: { title: \"Pushalot\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushalot.com\" } },\n [_vm._v(\"Pushalot\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushalot is a platform for receiving custom push notifications to connected devices running Windows Phone or Windows 8.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushalot\",\n explanations: [\"Send Pushalot notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushalot, \"enabled\", $$v)\n },\n expression: \"notifiers.pushalot.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushalot.enabled,\n expression: \"notifiers.pushalot.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushalot-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushalot_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushalot_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushalot_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushalot authorization token\",\n id: \"pushalot_authorizationtoken\",\n explanations: [\n \"authorization token of your Pushalot account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.authToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"authToken\",\n $$v\n )\n },\n expression: \"notifiers.pushalot.authToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushalot-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushalot\",\n id: \"testPushalot\"\n },\n on: { click: _vm.testPushalot }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushbullet\",\n attrs: { title: \"Pushbullet\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.pushbullet.com\" } },\n [_vm._v(\"Pushbullet\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushbullet is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushbullet\",\n explanations: [\"Send pushbullet notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushbullet.enabled,\n expression: \"notifiers.pushbullet.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushbullet-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushbullet_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushbullet_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushbullet_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushbullet API key\",\n id: \"pushbullet_api\",\n explanations: [\n \"API key of your Pushbullet account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushbullet_device_list\",\n label: \"Pushbullet devices\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Update device list\",\n id: \"get-pushbullet-devices\"\n },\n on: {\n click: _vm.getPushbulletDeviceOptions\n }\n }),\n _vm._v(\" \"),\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushbullet.device,\n expression:\n \"notifiers.pushbullet.device\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushbullet_device_list\",\n name: \"pushbullet_device_list\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"device\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushbulletDeviceOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value },\n on: {\n change: function($event) {\n _vm.pushbulletTestInfo =\n \"Don't forget to save your new pushbullet settings.\"\n }\n }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"select device you wish to push to.\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushbullet-resultsfsf\" }\n },\n [_vm._v(_vm._s(_vm.pushbulletTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushbullet\",\n id: \"testPushbullet\"\n },\n on: { click: _vm.testPushbulletApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-join\",\n attrs: { title: \"Join\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://joaoapps.com/join/\" } },\n [_vm._v(\"Join\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Join is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_join\",\n explanations: [\"Send join notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"enabled\", $$v)\n },\n expression: \"notifiers.join.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.join.enabled,\n expression: \"notifiers.join.enabled\"\n }\n ],\n attrs: { id: \"content-use-join-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"join_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"join_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"join_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.join.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.join.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join API key\",\n id: \"join_api\",\n explanations: [\n \"API key of your Join account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"api\", $$v)\n },\n expression: \"notifiers.join.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join Device ID(s) key\",\n id: \"join_device\",\n explanations: [\n \"Enter DeviceID of the device(s) you wish to send notifications to, comma separated if using multiple.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.device,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"device\", $$v)\n },\n expression: \"notifiers.join.device\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testJoin-result\" }\n },\n [_vm._v(_vm._s(_vm.joinTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Join\",\n id: \"testJoin\"\n },\n on: { click: _vm.testJoinApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-freemobile\",\n attrs: { title: \"Free Mobile\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://mobile.free.fr/\" } },\n [_vm._v(\"Free Mobile\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Free Mobile is a famous French cellular network provider. It provides to their customer a free SMS API.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_freemobile\",\n explanations: [\"Send SMS notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.freemobile.enabled,\n expression: \"notifiers.freemobile.enabled\"\n }\n ],\n attrs: { id: \"content-use-freemobile-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"freemobile_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"freemobile_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"freemobile_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile customer ID\",\n id: \"freemobile_id\",\n explanations: [\n \"It's your Free Mobile customer ID (8 digits)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.id,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"id\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile API Key\",\n id: \"freemobile_apikey\",\n explanations: [\n \"Find your API Key in your customer portal.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testFreeMobile-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test SMS\",\n id: \"testFreeMobile\"\n },\n on: { click: _vm.testFreeMobile }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-telegram\",\n attrs: { title: \"Telegram\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://telegram.org/\" } },\n [_vm._v(\"Telegram\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Telegram is a cloud-based instant messaging service.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_telegram\",\n explanations: [\"Send Telegram notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"enabled\", $$v)\n },\n expression: \"notifiers.telegram.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.telegram.enabled,\n expression: \"notifiers.telegram.enabled\"\n }\n ],\n attrs: { id: \"content-use-telegram-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"telegram_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"telegram_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"telegram_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"User/group ID\",\n id: \"telegram_id\",\n explanations: [\n \"Contact @myidbot on Telegram to get an ID\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.id,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"id\", $$v)\n },\n expression: \"notifiers.telegram.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot API token\",\n id: \"telegram_apikey\",\n explanations: [\n \"Contact @BotFather on Telegram to set up one\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"api\", $$v)\n },\n expression: \"notifiers.telegram.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTelegram-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Telegram\",\n id: \"testTelegram\"\n },\n on: { click: _vm.testTelegram }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-discord\",\n attrs: { title: \"Discord\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://discordapp.com/\" } },\n [_vm._v(\"Discord\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Discord is a cloud-based All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone..\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_discord\",\n explanations: [\"Send Discord notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"enabled\", $$v)\n },\n expression: \"notifiers.discord.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.discord.enabled,\n expression: \"notifiers.discord.enabled\"\n }\n ],\n attrs: { id: \"content-use-discord-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"discord_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.discord.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"discord_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"discord_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.discord\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Channel webhook\",\n id: \"discord_webhook\",\n explanations: [\n \"Add a webhook to a channel, use the returned url here\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.discord.webhook\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Text to speech\",\n id: \"discord_tts\",\n explanations: [\n \"Use discord text to speech feature\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.tts,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"tts\", $$v)\n },\n expression: \"notifiers.discord.tts\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot username\",\n id: \"discord_name\",\n explanations: [\n \"Create a username for the Discord Bot to use\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"name\", $$v)\n },\n expression: \"notifiers.discord.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testDiscord-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Discord\",\n id: \"testDiscord\"\n },\n on: { click: _vm.testDiscord }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"social\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-twitter\",\n attrs: { title: \"Twitter\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.twitter.com\" } },\n [_vm._v(\"Twitter\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_twitter\",\n explanations: [\n \"Should Medusa post tweets on Twitter?\",\n \"Note: you may want to use a secondary account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"enabled\", $$v)\n },\n expression: \"notifiers.twitter.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.twitter.enabled,\n expression: \"notifiers.twitter.enabled\"\n }\n ],\n attrs: { id: \"content-use-twitter\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"twitter_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.twitter.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"twitter_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"twitter_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.twitter\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Send direct message\",\n id: \"twitter_usedm\",\n explanations: [\n \"send a notification via Direct Message, not via status update\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.directMessage,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"directMessage\",\n $$v\n )\n },\n expression: \"notifiers.twitter.directMessage\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Send DM to\",\n id: \"twitter_dmto\",\n explanations: [\n \"Twitter account to send Direct Messages to (must follow you)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.dmto,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"dmto\", $$v)\n },\n expression: \"notifiers.twitter.dmto\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep1\",\n label: \"Step 1\"\n }\n },\n [\n _c(\n \"span\",\n { staticStyle: { \"font-size\": \"11px\" } },\n [\n _vm._v(\n 'Click the \"Request Authorization\" button. '\n ),\n _c(\"br\"),\n _vm._v(\n \"This will open a new page containing an auth key. \"\n ),\n _c(\"br\"),\n _vm._v(\n \"Note: if nothing happens check your popup blocker.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Request Authorization\",\n id: \"twitter-step-1\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep1($event)\n }\n }\n })\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep2\",\n label: \"Step 2\"\n }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.twitterKey,\n expression: \"twitterKey\"\n }\n ],\n staticClass:\n \"form-control input-sm max-input350\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n id: \"twitter_key\",\n placeholder:\n \"Enter the key Twitter gave you, and click 'Verify Key'\"\n },\n domProps: { value: _vm.twitterKey },\n on: {\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.twitterKey = $event.target.value\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Verify Key\",\n id: \"twitter-step-2\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep2($event)\n }\n }\n })\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", {\n staticClass: \"testNotification\",\n attrs: { id: \"testTwitter-result\" },\n domProps: {\n innerHTML: _vm._s(_vm.twitterTestInfo)\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Twitter\",\n id: \"testTwitter\"\n },\n on: { click: _vm.twitterTest }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-trakt\",\n attrs: { title: \"Trakt\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://trakt.tv/\" } },\n [_vm._v(\"Trakt\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_trakt\",\n explanations: [\"Send Trakt.tv notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"enabled\", $$v)\n },\n expression: \"notifiers.trakt.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.enabled,\n expression: \"notifiers.trakt.enabled\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"trakt_username\",\n explanations: [\n \"username of your Trakt account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.trakt.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_pin\",\n label: \"Trakt PIN\"\n }\n },\n [\n _c(\"input\", {\n staticClass:\n \"form-control input-sm max-input250\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n name: \"trakt_pin\",\n id: \"trakt_pin\",\n value: \"\",\n disabled: _vm.notifiers.trakt.accessToken\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: _vm.traktNewTokenMessage,\n id: \"TraktGetPin\"\n },\n on: { click: _vm.TraktGetPin }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa hide\",\n attrs: {\n type: \"button\",\n value: \"Authorize Medusa\",\n id: \"authTrakt\"\n },\n on: { click: _vm.authTrakt }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"PIN code to authorize Medusa to access Trakt on your behalf.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n label: \"API Timeout\",\n id: \"trakt_timeout\",\n explanations: [\n \"Seconds to wait for Trakt API to respond. (Use 0 to wait forever)\"\n ]\n },\n model: {\n value: _vm.notifiers.trakt.timeout,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"timeout\",\n $$v\n )\n },\n expression: \"notifiers.trakt.timeout\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Default indexer\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.defaultIndexer,\n expression:\n \"notifiers.trakt.defaultIndexer\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_default_indexer\",\n name: \"trakt_default_indexer\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"defaultIndexer\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktIndexersOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync libraries\",\n id: \"trakt_sync\",\n explanations: [\n \"Sync your Medusa show library with your Trakt collection.\",\n \"Note: Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\",\n \"Kodi detects that the episode was deleted and removes from collection which causes Medusa to re-add it. This causes a loop between Medusa and Kodi adding and deleting the episode.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.sync,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"sync\", $$v)\n },\n expression: \"notifiers.trakt.sync\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.sync,\n expression: \"notifiers.trakt.sync\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove Episodes From Collection\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"Remove an Episode from your Trakt Collection if it is not in your Medusa Library.\",\n \"Note:Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync watchlist\",\n id: \"trakt_sync_watchlist\",\n explanations: [\n \"Sync your Medusa library with your Trakt Watchlist (either Show and Episode).\",\n \"Episode will be added on watch list when wanted or snatched and will be removed when downloaded\",\n \"Note: By design, Trakt automatically removes episodes and/or shows from watchlist as soon you have watched them.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.syncWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"syncWatchlist\",\n $$v\n )\n },\n expression: \"notifiers.trakt.syncWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.syncWatchlist,\n expression:\n \"notifiers.trakt.syncWatchlist\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Watchlist add method\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.methodAdd,\n expression:\n \"notifiers.trakt.methodAdd\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_method_add\",\n name: \"trakt_method_add\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"methodAdd\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktMethodOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"method in which to download episodes for new shows.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove episode\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"remove an episode from your watchlist after it's downloaded.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove series\",\n id: \"trakt_remove_serieslist\",\n explanations: [\n \"remove the whole series from your watchlist after any download.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeSerieslist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeSerieslist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeSerieslist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove watched show\",\n id: \"trakt_remove_show_from_application\",\n explanations: [\n \"remove the show from Medusa if it's ended and completely watched\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt\n .removeShowFromApplication,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeShowFromApplication\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeShowFromApplication\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Start paused\",\n id: \"trakt_start_paused\",\n explanations: [\n \"shows grabbed from your trakt watchlist start paused.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.startPaused,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"startPaused\",\n $$v\n )\n },\n expression: \"notifiers.trakt.startPaused\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Trakt blackList name\",\n id: \"trakt_blacklist_name\",\n explanations: [\n \"Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' & 'Add Recommended Shows' pages\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.blacklistName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"blacklistName\",\n $$v\n )\n },\n expression: \"notifiers.trakt.blacklistName\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTrakt-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Trakt\",\n id: \"testTrakt\"\n },\n on: { click: _vm.testTrakt }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Force Sync\",\n id: \"forceSync\"\n },\n on: { click: _vm.traktForceSync }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n attrs: { type: \"hidden\", id: \"trakt_pin_url\" },\n domProps: { value: _vm.notifiers.trakt.pinUrl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-email\",\n attrs: { title: \"Email\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://en.wikipedia.org/wiki/Comparison_of_webmail_providers\"\n }\n },\n [_vm._v(\"Email\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Allows configuration of email notifications on a per show basis.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_email\",\n explanations: [\"Send email notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"enabled\", $$v)\n },\n expression: \"notifiers.email.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.email.enabled,\n expression: \"notifiers.email.enabled\"\n }\n ],\n attrs: { id: \"content-use-email\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"email_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"email_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"email_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.email\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.email.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP host\",\n id: \"email_host\",\n explanations: [\n \"hostname of your SMTP email server.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"host\", $$v)\n },\n expression: \"notifiers.email.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n min: 1,\n step: 1,\n label: \"SMTP port\",\n id: \"email_port\",\n explanations: [\n \"port number used to connect to your SMTP host.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.port,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"port\", $$v)\n },\n expression: \"notifiers.email.port\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP from\",\n id: \"email_from\",\n explanations: [\n \"sender email address, some hosts require a real address.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.from,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"from\", $$v)\n },\n expression: \"notifiers.email.from\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Use TLS\",\n id: \"email_tls\",\n explanations: [\"check to use TLS encryption.\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.tls,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"tls\", $$v)\n },\n expression: \"notifiers.email.tls\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP username\",\n id: \"email_username\",\n explanations: [\n \"(optional) your SMTP server username.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.email.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"SMTP password\",\n id: \"email_password\",\n explanations: [\n \"(optional) your SMTP server password.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.email.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_list\",\n label: \"Global email list\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.notifiers.email.addressList\n },\n on: { change: _vm.emailUpdateAddressList }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Email Subject\",\n id: \"email_subject\",\n explanations: [\n \"Use a custom subject for some privacy protection?\",\n \"(Leave blank for the default Medusa subject)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.subject,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"subject\",\n $$v\n )\n },\n expression: \"notifiers.email.subject\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_show\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.emailUpdateShowEmail($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.emailSelectedShowAdresses\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"email\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEmail-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Email\",\n id: \"testEmail\"\n },\n on: { click: _vm.testEmail }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-slack\",\n attrs: { title: \"Slack\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://slack.com\" } },\n [_vm._v(\"Slack\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"Slack is a messaging app for teams.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_slack_client\",\n explanations: [\"Send Slack notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.slack, \"enabled\", $$v)\n },\n expression: \"notifiers.slack.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.slack.enabled,\n expression: \"notifiers.slack.enabled\"\n }\n ],\n attrs: { id: \"content-use-slack-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"slack_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"slack_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"slack_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.slack\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.slack.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Slack Incoming Webhook\",\n id: \"slack_webhook\",\n explanations: [\n \"Create an incoming webhook, to communicate with your slack channel.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.slack.webhook\"\n }\n },\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://my.slack.com/services/new/incoming-webhook\"\n }\n },\n [\n _vm._v(\n \"https://my.slack.com/services/new/incoming-webhook/\"\n )\n ]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testSlack-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Slack\",\n id: \"testSlack\"\n },\n on: { click: _vm.testSlack }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"br\"),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"br\")\n ])\n ]\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clearfix\" })\n ],\n 1\n )\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"label\",\n { staticClass: \"col-sm-2 control-label\", attrs: { for: \"kodi_host\" } },\n [_c(\"span\", [_vm._v(\"KODI IP:Port\")])]\n )\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"clear-left\" }, [\n _c(\"p\", [\n _c(\"b\", [_vm._v(\"Note:\")]),\n _vm._v(\" some Plex Home Theaters \"),\n _c(\"b\", { staticClass: \"boldest\" }, [_vm._v(\"do not\")]),\n _vm._v(\" support notifications e.g. Plexapp for Samsung TVs\")\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"render\": () => /* binding */ render,\n/* harmony export */ \"staticRenderFns\": () => /* binding */ staticRenderFns\n/* harmony export */ });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"config-notifications\" } },\n [\n _c(\"vue-snotify\"),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"config\" } }, [\n _c(\"div\", { attrs: { id: \"config-content\" } }, [\n _c(\n \"form\",\n {\n attrs: { id: \"configForm\", method: \"post\" },\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.save()\n }\n }\n },\n [\n _c(\"div\", { attrs: { id: \"config-components\" } }, [\n _c(\"ul\", [\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#home-theater-nas\" } }, [\n _vm._v(\"Home Theater / NAS\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#devices\" } }, [\n _vm._v(\"Devices\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#social\" } }, [\n _vm._v(\"Social\")\n ])\n ],\n 1\n )\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"home-theater-nas\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-kodi\",\n attrs: { title: \"KODI\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://kodi.tv\" } },\n [_vm._v(\"KODI\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A free and open source cross-platform media center and home entertainment system software with a 10-foot user interface designed for the living-room TV.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_kodi\",\n explanations: [\"Send KODI commands?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.kodi, \"enabled\", $$v)\n },\n expression: \"notifiers.kodi.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.kodi.enabled,\n expression: \"notifiers.kodi.enabled\"\n }\n ],\n attrs: { id: \"content-use-kodi\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Always on\",\n id: \"kodi_always_on\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.alwaysOn,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"alwaysOn\",\n $$v\n )\n },\n expression: \"notifiers.kodi.alwaysOn\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"kodi_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"kodi_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"kodi_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.kodi.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.kodi.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update library\",\n id: \"kodi_update_library\",\n explanations: [\n \"update KODI library when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.library,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"library\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.library\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Full library update\",\n id: \"kodi_update_full\",\n explanations: [\n \"perform a full library update if update per-show fails?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.full,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"full\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.full\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Clean library\",\n id: \"kodi_clean_library\",\n explanations: [\n \"clean KODI library when replaces a already downloaded episode?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.cleanLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"cleanLibrary\",\n $$v\n )\n },\n expression: \"notifiers.kodi.cleanLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Only update first host\",\n id: \"kodi_update_onlyfirst\",\n explanations: [\n \"only send library updates/clean to the first active host?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.onlyFirst,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"onlyFirst\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.onlyFirst\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"col-sm-10 content\" },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"kodi_host\",\n id: \"kodi_host\",\n \"list-items\": _vm.notifiers.kodi.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.kodi.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"host running KODI (eg. 192.168.1.100:8080)\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"kodi_username\",\n explanations: [\n \"username for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.kodi.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"kodi_password\",\n explanations: [\n \"password for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.kodi.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testKODI-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test KODI\",\n id: \"testKODI\"\n },\n on: { click: _vm.testKODI }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plex\",\n attrs: { title: \"Plex Media Server\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Media Server\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Experience your media on a visually stunning, easy to use interface on your Mac connected to your TV. Your media library has never looked this good!\"\n )\n ]),\n _vm._v(\" \"),\n _vm.notifiers.plex.server.enabled\n ? _c(\"p\", { staticClass: \"plexinfo\" }, [\n _vm._v(\n \"For sending notifications to Plex Home Theater (PHT) clients, use the KODI notifier with port \"\n ),\n _c(\"b\", [_vm._v(\"3005\")]),\n _vm._v(\".\")\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_server\",\n explanations: [\"Send Plex server notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.server.enabled,\n expression: \"notifiers.plex.server.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-server\" }\n },\n [\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Plex Media Server Auth Token\",\n id: \"plex_server_token\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.token,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"token\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.token\"\n }\n },\n [\n _c(\"p\", [_vm._v(\"Auth Token used by plex\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\n \"span\",\n [\n _vm._v(\"See: \"),\n _c(\n \"app-link\",\n {\n staticClass: \"wiki\",\n attrs: {\n href:\n \"https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token\"\n }\n },\n [\n _c(\"strong\", [\n _vm._v(\n \"Finding your account token\"\n )\n ])\n ]\n )\n ],\n 1\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_server_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_server_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update Library\",\n id: \"plex_update_library\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.server.updateLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"updateLibrary\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.server.updateLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_server_host\",\n label: \"Plex Media Server IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_server_host\",\n id: \"plex_server_host\",\n \"list-items\":\n _vm.notifiers.plex.server.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.server.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Media Server\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.1:32400, 192.168.1.2:32400)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"plex_server_https\",\n explanations: [\n \"use https for plex media server requests?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.https,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"https\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.https\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPMS-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Media Server(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Media Server\",\n id: \"testPMS\"\n },\n on: { click: _vm.testPMS }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clear-left\" }, [\n _vm._v(\" \")\n ])\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plexth\",\n attrs: { title: \"Plex Media Client\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Home Theater\")]\n )\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_client\",\n explanations: [\n \"Send Plex Home Theater notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.client.enabled,\n expression: \"notifiers.plex.client.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"plex_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"plex_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"plex_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_client_host\",\n label: \"Plex Home Theater IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_client_host\",\n id: \"plex_client_host\",\n \"list-items\":\n _vm.notifiers.plex.client.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.client.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Home Theater\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.100:3000, 192.168.1.101:3000)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_client_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_client_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPHT-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Home Theater(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Home Theater\",\n id: \"testPHT\"\n },\n on: { click: _vm.testPHT }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _vm._m(1)\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-emby\",\n attrs: { title: \"Emby\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://emby.media\" } },\n [_vm._v(\"Emby\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A home media server built using other popular open source technologies.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_emby\",\n explanations: [\"Send update commands to Emby?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"enabled\", $$v)\n },\n expression: \"notifiers.emby.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.emby.enabled,\n expression: \"notifiers.emby.enabled\"\n }\n ],\n attrs: { id: \"content_use_emby\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Emby IP:Port\",\n id: \"emby_host\",\n explanations: [\n \"host running Emby (eg. 192.168.1.100:8096)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"host\", $$v)\n },\n expression: \"notifiers.emby.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: { label: \"Api Key\", id: \"emby_apikey\" },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.apiKey,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"apiKey\", $$v)\n },\n expression: \"notifiers.emby.apiKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEMBY-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Emby\",\n id: \"testEMBY\"\n },\n on: { click: _vm.testEMBY }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJ\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmj\",\n explanations: [\"Send update commands to NMJ?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"enabled\", $$v)\n },\n expression: \"notifiers.nmj.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmj.enabled,\n expression: \"notifiers.nmj.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmj\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmj_host\",\n explanations: [\n \"IP address of Popcorn 200-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"host\", $$v)\n },\n expression: \"notifiers.nmj.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"settingsNMJ\",\n label: \"Get settings\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Get Settings\",\n id: \"settingsNMJ\"\n },\n on: { click: _vm.settingsNMJ }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on and NMJ running.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ database\",\n id: \"nmj_database\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.database,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"database\", $$v)\n },\n expression: \"notifiers.nmj.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ mount\",\n id: \"nmj_mount\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.mount,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"mount\", $$v)\n },\n expression: \"notifiers.nmj.mount\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJ-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJ\",\n id: \"testNMJ\"\n },\n on: { click: _vm.testNMJ }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox v2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJv2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJv2, is the official media jukebox interface made available for the Popcorn Hour 300 & 400-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmjv2\",\n explanations: [\n \"Send popcorn hour (nmjv2) notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"enabled\", $$v)\n },\n expression: \"notifiers.nmjv2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmjv2.enabled,\n expression: \"notifiers.nmjv2.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmjv2\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmjv2_host\",\n explanations: [\n \"IP address of Popcorn 300/400-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"host\", $$v)\n },\n expression: \"notifiers.nmjv2.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_location\",\n label: \"Database location\"\n }\n },\n [\n _c(\n \"label\",\n {\n staticClass: \"space-right\",\n attrs: { for: \"NMJV2_DBLOC_A\" }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"local\",\n id: \"NMJV2_DBLOC_A\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Local Media\\n \"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"label\",\n { attrs: { for: \"NMJV2_DBLOC_B\" } },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"network\",\n id: \"NMJV2_DBLOC_B\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Network Media\\n \"\n )\n ]\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_instance\",\n label: \"Database instance\"\n }\n },\n [\n _c(\n \"select\",\n {\n staticClass: \"form-control input-sm\",\n attrs: { id: \"NMJv2db_instance\" }\n },\n [\n _c(\"option\", { attrs: { value: \"0\" } }, [\n _vm._v(\"#1 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"1\" } }, [\n _vm._v(\"#2 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"2\" } }, [\n _vm._v(\"#3 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"3\" } }, [\n _vm._v(\"#4 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"4\" } }, [\n _vm._v(\"#5 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"5\" } }, [\n _vm._v(\"#6 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"6\" } }, [\n _vm._v(\"#7 \")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"adjust this value if the wrong database is selected.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"get_nmjv2_find_database\",\n label: \"Find database\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Find Database\",\n id: \"settingsNMJv2\"\n },\n on: { click: _vm.settingsNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJv2 database\",\n id: \"nmjv2_database\",\n explanations: [\n \"automatically filled via the 'Find Database' buttons.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.database,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.nmjv2,\n \"database\",\n $$v\n )\n },\n expression: \"notifiers.nmjv2.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJv2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJv2\",\n id: \"testNMJv2\"\n },\n on: { click: _vm.testNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno1\",\n attrs: { title: \"Synology\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"The Synology DiskStation NAS.\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Indexer is the daemon running on the Synology NAS to build its media database.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"use_synoindex\",\n explanations: [\n \"Note: requires Medusa to be running on your Synology NAS.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synologyIndex.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synologyIndex,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.synologyIndex.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synologyIndex.enabled,\n expression: \"notifiers.synologyIndex.enabled\"\n }\n ],\n attrs: { id: \"content_use_synoindex\" }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ]\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno2\",\n attrs: { title: \"Synology Indexer\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology Notifier\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Notifier is the notification system of Synology DSM\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_synologynotifier\",\n explanations: [\n \"Send notifications to the Synology Notifier?\",\n \"Note: requires Medusa to be running on your Synology DSM.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.synology, \"enabled\", $$v)\n },\n expression: \"notifiers.synology.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synology.enabled,\n expression: \"notifiers.synology.enabled\"\n }\n ],\n attrs: { id: \"content-use-synology-notifier\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"synology_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"synology_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pytivo\",\n attrs: { title: \"pyTivo\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://pytivo.sourceforge.net/wiki/index.php/PyTivo\"\n }\n },\n [_vm._v(\"pyTivo\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pytivo\",\n explanations: [\"Send notifications to pyTivo?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"enabled\", $$v)\n },\n expression: \"notifiers.pyTivo.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pyTivo.enabled,\n expression: \"notifiers.pyTivo.enabled\"\n }\n ],\n attrs: { id: \"content-use-pytivo\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo IP:Port\",\n id: \"pytivo_host\",\n explanations: [\n \"host running pyTivo (eg. 192.168.1.1:9032)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"host\", $$v)\n },\n expression: \"notifiers.pyTivo.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo share name\",\n id: \"pytivo_name\",\n explanations: [\n \"(Messages & Settings > Account & System Information > System Information > DVR name)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.shareName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pyTivo,\n \"shareName\",\n $$v\n )\n },\n expression: \"notifiers.pyTivo.shareName\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Tivo name\",\n id: \"pytivo_tivo_name\",\n explanations: [\n \"value used in pyTivo Web Configuration to name the share.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"name\", $$v)\n },\n expression: \"notifiers.pyTivo.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"devices\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-growl\",\n attrs: { title: \"Growl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://growl.info/\" } },\n [_vm._v(\"Growl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A cross-platform unobtrusive global notification system.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_growl_client\",\n explanations: [\"Send Growl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"enabled\", $$v)\n },\n expression: \"notifiers.growl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.growl.enabled,\n expression: \"notifiers.growl.enabled\"\n }\n ],\n attrs: { id: \"content-use-growl-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"growl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"growl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"growl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.growl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.growl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Growl IP:Port\",\n id: \"growl_host\",\n explanations: [\n \"host running Growl (eg. 192.168.1.100:23053)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"host\", $$v)\n },\n expression: \"notifiers.growl.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"growl_password\",\n explanations: [\n \"may leave blank if Medusa is on the same host.\",\n \"otherwise Growl requires a password to be used.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.growl.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testGrowl-result\" }\n },\n [\n _vm._v(\n \"Click below to register and test Growl, this is required for Growl notifications to work.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Register Growl\",\n id: \"testGrowl\"\n },\n on: { click: _vm.testGrowl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-prowl\",\n attrs: { title: \"Prowl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://www.prowlapp.com/\" } },\n [_vm._v(\"Prowl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"A Growl client for iOS.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_prowl\",\n explanations: [\"Send Prowl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.prowl, \"enabled\", $$v)\n },\n expression: \"notifiers.prowl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.prowl.enabled,\n expression: \"notifiers.prowl.enabled\"\n }\n ],\n attrs: { id: \"content-use-prowl\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"prowl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"prowl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"prowl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.prowl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.prowl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Prowl Message Title\",\n id: \"prowl_message_title\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.messageTitle,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"messageTitle\",\n $$v\n )\n },\n expression: \"notifiers.prowl.messageTitle\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_api\",\n label: \"Api\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl_api\",\n id: \"prowl_api\",\n \"csv-enabled\": \"\",\n \"list-items\": _vm.notifiers.prowl.api\n },\n on: { change: _vm.onChangeProwlApi }\n }),\n _vm._v(\" \"),\n _c(\n \"span\",\n [\n _vm._v(\n \"Prowl API(s) listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\n \" shows.\\n Your Prowl API key is available at:\\n \"\n ),\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://www.prowlapp.com/api_settings.php\"\n }\n },\n [\n _vm._v(\n \"\\n https://www.prowlapp.com/api_settings.php\"\n )\n ]\n ),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_show_notification_list\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.prowlUpdateApiKeys($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl-show-list\",\n id: \"prowl-show-list\",\n \"list-items\":\n _vm.prowlSelectedShowApiKeys\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"prowl\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Configure per-show notifications here by entering Prowl API key(s), after selecting a show in the drop-down box.\\n Be sure to activate the 'Save for this show' button below after each entry.\\n \"\n ),\n _c(\"span\", [\n _vm._v(\n \"The values are automatically saved when adding the api key.\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_priority\",\n label: \"Prowl priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.prowl.priority,\n expression: \"notifiers.prowl.priority\"\n }\n ],\n staticClass: \"form-control input-sm\",\n attrs: {\n id: \"prowl_priority\",\n name: \"prowl_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.prowl,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.prowlPriorityOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Prowl messages from Medusa.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testProwl-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Prowl\",\n id: \"testProwl\"\n },\n on: { click: _vm.testProwl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-libnotify\",\n attrs: { title: \"Libnotify\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://library.gnome.org/devel/libnotify/\"\n }\n },\n [_vm._v(\"Libnotify\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"p\",\n [\n _vm._v(\n \"The standard desktop notification API for Linux/*nix systems. This notifier will only function if the pynotify module is installed (Ubuntu/Debian package \"\n ),\n _c(\n \"app-link\",\n { attrs: { href: \"apt:python-notify\" } },\n [_vm._v(\"python-notify\")]\n ),\n _vm._v(\").\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_libnotify_client\",\n explanations: [\"Send Libnotify notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.libnotify.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.libnotify.enabled,\n expression: \"notifiers.libnotify.enabled\"\n }\n ],\n attrs: { id: \"content-use-libnotify\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"libnotify_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"libnotify_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"libnotify_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testLibnotify-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Libnotify\",\n id: \"testLibnotify\"\n },\n on: { click: _vm.testLibnotify }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushover\",\n attrs: { title: \"Pushover\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushover.net/\" } },\n [_vm._v(\"Pushover\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushover makes it easy to send real-time notifications to your Android and iOS devices.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushover_client\",\n explanations: [\"Send Pushover notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushover, \"enabled\", $$v)\n },\n expression: \"notifiers.pushover.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushover.enabled,\n expression: \"notifiers.pushover.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushover\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushover_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushover_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushover_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushover User Key\",\n id: \"pushover_userkey\",\n explanations: [\n \"User Key of your Pushover account\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.userKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"userKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.userKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Pushover API Key\",\n id: \"pushover_apikey\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.apiKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"apiKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.apiKey\"\n }\n },\n [\n _c(\n \"span\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://pushover.net/apps/build/\"\n }\n },\n [_c(\"b\", [_vm._v(\"Click here\")])]\n ),\n _vm._v(\" to create a Pushover API key\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_device\",\n label: \"Pushover Devices\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"pushover_device\",\n id: \"pushover_device\",\n \"list-items\":\n _vm.notifiers.pushover.device\n },\n on: {\n change: function($event) {\n _vm.notifiers.pushover.device = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"List of pushover devices you want to send notifications to\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_sound\",\n label: \"Pushover notification sound\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.pushover.sound,\n expression: \"notifiers.pushover.sound\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_sound\",\n name: \"pushover_sound\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"sound\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.pushoverSoundOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"Choose notification sound to use\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_priority\",\n label: \"Pushover notification priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushover.priority,\n expression:\n \"notifiers.pushover.priority\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_priority\",\n name: \"pushover_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushoverPriorityOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Pushover messages from Medusa\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushover-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushover\",\n id: \"testPushover\"\n },\n on: { click: _vm.testPushover }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-boxcar2\",\n attrs: { title: \"Boxcar 2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://new.boxcar.io/\" } },\n [_vm._v(\"Boxcar 2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Read your messages where and when you want them!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_boxcar2\",\n explanations: [\"Send boxcar2 notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.boxcar2, \"enabled\", $$v)\n },\n expression: \"notifiers.boxcar2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.boxcar2.enabled,\n expression: \"notifiers.boxcar2.enabled\"\n }\n ],\n attrs: { id: \"content-use-boxcar2-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"boxcar2_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"boxcar2_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"boxcar2_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.boxcar2\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Boxcar2 Access token\",\n id: \"boxcar2_accesstoken\",\n explanations: [\n \"access token for your Boxcar account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.accessToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"accessToken\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.accessToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testBoxcar2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Boxcar\",\n id: \"testBoxcar2\"\n },\n on: { click: _vm.testBoxcar2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushalot\",\n attrs: { title: \"Pushalot\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushalot.com\" } },\n [_vm._v(\"Pushalot\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushalot is a platform for receiving custom push notifications to connected devices running Windows Phone or Windows 8.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushalot\",\n explanations: [\"Send Pushalot notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushalot, \"enabled\", $$v)\n },\n expression: \"notifiers.pushalot.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushalot.enabled,\n expression: \"notifiers.pushalot.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushalot-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushalot_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushalot_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushalot_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushalot authorization token\",\n id: \"pushalot_authorizationtoken\",\n explanations: [\n \"authorization token of your Pushalot account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.authToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"authToken\",\n $$v\n )\n },\n expression: \"notifiers.pushalot.authToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushalot-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushalot\",\n id: \"testPushalot\"\n },\n on: { click: _vm.testPushalot }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushbullet\",\n attrs: { title: \"Pushbullet\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.pushbullet.com\" } },\n [_vm._v(\"Pushbullet\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushbullet is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushbullet\",\n explanations: [\"Send pushbullet notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushbullet.enabled,\n expression: \"notifiers.pushbullet.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushbullet-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushbullet_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushbullet_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushbullet_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushbullet API key\",\n id: \"pushbullet_api\",\n explanations: [\n \"API key of your Pushbullet account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushbullet_device_list\",\n label: \"Pushbullet devices\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Update device list\",\n id: \"get-pushbullet-devices\"\n },\n on: {\n click: _vm.getPushbulletDeviceOptions\n }\n }),\n _vm._v(\" \"),\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushbullet.device,\n expression:\n \"notifiers.pushbullet.device\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushbullet_device_list\",\n name: \"pushbullet_device_list\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"device\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushbulletDeviceOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value },\n on: {\n change: function($event) {\n _vm.pushbulletTestInfo =\n \"Don't forget to save your new pushbullet settings.\"\n }\n }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"select device you wish to push to.\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushbullet-resultsfsf\" }\n },\n [_vm._v(_vm._s(_vm.pushbulletTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushbullet\",\n id: \"testPushbullet\"\n },\n on: { click: _vm.testPushbulletApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-join\",\n attrs: { title: \"Join\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://joaoapps.com/join/\" } },\n [_vm._v(\"Join\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Join is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_join\",\n explanations: [\"Send join notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"enabled\", $$v)\n },\n expression: \"notifiers.join.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.join.enabled,\n expression: \"notifiers.join.enabled\"\n }\n ],\n attrs: { id: \"content-use-join-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"join_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"join_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"join_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.join.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.join.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join API key\",\n id: \"join_api\",\n explanations: [\n \"API key of your Join account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"api\", $$v)\n },\n expression: \"notifiers.join.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join Device ID(s) key\",\n id: \"join_device\",\n explanations: [\n \"Enter DeviceID of the device(s) you wish to send notifications to, comma separated if using multiple.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.device,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"device\", $$v)\n },\n expression: \"notifiers.join.device\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testJoin-result\" }\n },\n [_vm._v(_vm._s(_vm.joinTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Join\",\n id: \"testJoin\"\n },\n on: { click: _vm.testJoinApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-freemobile\",\n attrs: { title: \"Free Mobile\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://mobile.free.fr/\" } },\n [_vm._v(\"Free Mobile\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Free Mobile is a famous French cellular network provider. It provides to their customer a free SMS API.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_freemobile\",\n explanations: [\"Send SMS notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.freemobile.enabled,\n expression: \"notifiers.freemobile.enabled\"\n }\n ],\n attrs: { id: \"content-use-freemobile-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"freemobile_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"freemobile_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"freemobile_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile customer ID\",\n id: \"freemobile_id\",\n explanations: [\n \"It's your Free Mobile customer ID (8 digits)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.id,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"id\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile API Key\",\n id: \"freemobile_apikey\",\n explanations: [\n \"Find your API Key in your customer portal.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testFreeMobile-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test SMS\",\n id: \"testFreeMobile\"\n },\n on: { click: _vm.testFreeMobile }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-telegram\",\n attrs: { title: \"Telegram\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://telegram.org/\" } },\n [_vm._v(\"Telegram\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Telegram is a cloud-based instant messaging service.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_telegram\",\n explanations: [\"Send Telegram notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"enabled\", $$v)\n },\n expression: \"notifiers.telegram.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.telegram.enabled,\n expression: \"notifiers.telegram.enabled\"\n }\n ],\n attrs: { id: \"content-use-telegram-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"telegram_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"telegram_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"telegram_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"User/group ID\",\n id: \"telegram_id\",\n explanations: [\n \"Contact @myidbot on Telegram to get an ID\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.id,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"id\", $$v)\n },\n expression: \"notifiers.telegram.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot API token\",\n id: \"telegram_apikey\",\n explanations: [\n \"Contact @BotFather on Telegram to set up one\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"api\", $$v)\n },\n expression: \"notifiers.telegram.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTelegram-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Telegram\",\n id: \"testTelegram\"\n },\n on: { click: _vm.testTelegram }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-discord\",\n attrs: { title: \"Discord\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://discordapp.com/\" } },\n [_vm._v(\"Discord\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Discord is a cloud-based All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone..\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_discord\",\n explanations: [\"Send Discord notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"enabled\", $$v)\n },\n expression: \"notifiers.discord.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.discord.enabled,\n expression: \"notifiers.discord.enabled\"\n }\n ],\n attrs: { id: \"content-use-discord-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"discord_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.discord.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"discord_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"discord_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.discord\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Channel webhook\",\n id: \"discord_webhook\",\n explanations: [\n \"Add a webhook to a channel, use the returned url here\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.discord.webhook\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Text to speech\",\n id: \"discord_tts\",\n explanations: [\n \"Use discord text to speech feature\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.tts,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"tts\", $$v)\n },\n expression: \"notifiers.discord.tts\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot username\",\n id: \"discord_name\",\n explanations: [\n \"Create a username for the Discord Bot to use\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"name\", $$v)\n },\n expression: \"notifiers.discord.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testDiscord-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Discord\",\n id: \"testDiscord\"\n },\n on: { click: _vm.testDiscord }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"social\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-twitter\",\n attrs: { title: \"Twitter\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.twitter.com\" } },\n [_vm._v(\"Twitter\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_twitter\",\n explanations: [\n \"Should Medusa post tweets on Twitter?\",\n \"Note: you may want to use a secondary account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"enabled\", $$v)\n },\n expression: \"notifiers.twitter.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.twitter.enabled,\n expression: \"notifiers.twitter.enabled\"\n }\n ],\n attrs: { id: \"content-use-twitter\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"twitter_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.twitter.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"twitter_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"twitter_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.twitter\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Send direct message\",\n id: \"twitter_usedm\",\n explanations: [\n \"send a notification via Direct Message, not via status update\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.directMessage,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"directMessage\",\n $$v\n )\n },\n expression: \"notifiers.twitter.directMessage\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Send DM to\",\n id: \"twitter_dmto\",\n explanations: [\n \"Twitter account to send Direct Messages to (must follow you)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.dmto,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"dmto\", $$v)\n },\n expression: \"notifiers.twitter.dmto\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep1\",\n label: \"Step 1\"\n }\n },\n [\n _c(\n \"span\",\n { staticStyle: { \"font-size\": \"11px\" } },\n [\n _vm._v(\n 'Click the \"Request Authorization\" button. '\n ),\n _c(\"br\"),\n _vm._v(\n \"This will open a new page containing an auth key. \"\n ),\n _c(\"br\"),\n _vm._v(\n \"Note: if nothing happens check your popup blocker.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Request Authorization\",\n id: \"twitter-step-1\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep1($event)\n }\n }\n })\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep2\",\n label: \"Step 2\"\n }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.twitterKey,\n expression: \"twitterKey\"\n }\n ],\n staticClass:\n \"form-control input-sm max-input350\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n id: \"twitter_key\",\n placeholder:\n \"Enter the key Twitter gave you, and click 'Verify Key'\"\n },\n domProps: { value: _vm.twitterKey },\n on: {\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.twitterKey = $event.target.value\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Verify Key\",\n id: \"twitter-step-2\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep2($event)\n }\n }\n })\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", {\n staticClass: \"testNotification\",\n attrs: { id: \"testTwitter-result\" },\n domProps: {\n innerHTML: _vm._s(_vm.twitterTestInfo)\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Twitter\",\n id: \"testTwitter\"\n },\n on: { click: _vm.twitterTest }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\"a\", { attrs: { href: \"#trakt\" } }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-trakt\",\n attrs: { title: \"Trakt\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://trakt.tv/\" } },\n [_vm._v(\"Trakt\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_trakt\",\n explanations: [\"Send Trakt.tv notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"enabled\", $$v)\n },\n expression: \"notifiers.trakt.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.enabled,\n expression: \"notifiers.trakt.enabled\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_request_auth\",\n label: \"\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Connect to your trakt account\",\n id: \"Trakt\"\n },\n on: { click: _vm.TraktRequestDeviceCode }\n }),\n _vm._v(\" \"),\n _vm.traktRequestSend && _vm.traktUserCode\n ? _c(\n \"span\",\n { staticStyle: { display: \"inline\" } },\n [\n _vm._v(\n \"Use this code in the popup: \" +\n _vm._s(_vm.traktUserCode)\n )\n ]\n )\n : _vm._e(),\n _vm._v(\" \"),\n _vm.traktRequestSend &&\n _vm.traktUserCode &&\n _vm.traktRequestMessage\n ? _c(\"p\", [\n _vm._v(\n \"Trakt request status: \" +\n _vm._s(_vm.traktRequestMessage)\n )\n ])\n : _vm._e(),\n _vm._v(\" \"),\n _vm.traktRequestAuthenticated &&\n _vm.traktRequestMessage\n ? _c(\"p\", [\n _vm._v(_vm._s(_vm.traktRequestMessage))\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n label: \"API Timeout\",\n id: \"trakt_timeout\",\n explanations: [\n \"Seconds to wait for Trakt API to respond. (Use 0 to wait forever)\"\n ]\n },\n model: {\n value: _vm.notifiers.trakt.timeout,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"timeout\",\n $$v\n )\n },\n expression: \"notifiers.trakt.timeout\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Default indexer\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.defaultIndexer,\n expression:\n \"notifiers.trakt.defaultIndexer\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_default_indexer\",\n name: \"trakt_default_indexer\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"defaultIndexer\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktIndexersOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync libraries\",\n id: \"trakt_sync\",\n explanations: [\n \"Sync your Medusa show library with your Trakt collection.\",\n \"Note: Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\",\n \"Kodi detects that the episode was deleted and removes from collection which causes Medusa to re-add it. This causes a loop between Medusa and Kodi adding and deleting the episode.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.sync,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"sync\", $$v)\n },\n expression: \"notifiers.trakt.sync\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.sync,\n expression: \"notifiers.trakt.sync\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove Episodes From Collection\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"Remove an Episode from your Trakt Collection if it is not in your Medusa Library.\",\n \"Note:Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync watchlist\",\n id: \"trakt_sync_watchlist\",\n explanations: [\n \"Sync your Medusa library with your Trakt Watchlist (either Show and Episode).\",\n \"Episode will be added on watch list when wanted or snatched and will be removed when downloaded\",\n \"Note: By design, Trakt automatically removes episodes and/or shows from watchlist as soon you have watched them.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.syncWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"syncWatchlist\",\n $$v\n )\n },\n expression: \"notifiers.trakt.syncWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.syncWatchlist,\n expression:\n \"notifiers.trakt.syncWatchlist\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Watchlist add method\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.methodAdd,\n expression:\n \"notifiers.trakt.methodAdd\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_method_add\",\n name: \"trakt_method_add\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"methodAdd\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktMethodOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"method in which to download episodes for new shows.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove episode\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"remove an episode from your watchlist after it's downloaded.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove series\",\n id: \"trakt_remove_serieslist\",\n explanations: [\n \"remove the whole series from your watchlist after any download.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeSerieslist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeSerieslist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeSerieslist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove watched show\",\n id: \"trakt_remove_show_from_application\",\n explanations: [\n \"remove the show from Medusa if it's ended and completely watched\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt\n .removeShowFromApplication,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeShowFromApplication\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeShowFromApplication\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Start paused\",\n id: \"trakt_start_paused\",\n explanations: [\n \"shows grabbed from your trakt watchlist start paused.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.startPaused,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"startPaused\",\n $$v\n )\n },\n expression: \"notifiers.trakt.startPaused\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Trakt blackList name\",\n id: \"trakt_blacklist_name\",\n explanations: [\n \"Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' & 'Add Recommended Shows' pages\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.blacklistName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"blacklistName\",\n $$v\n )\n },\n expression: \"notifiers.trakt.blacklistName\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTrakt-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Trakt\",\n id: \"testTrakt\"\n },\n on: { click: _vm.testTrakt }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Force Sync\",\n id: \"forceSync\"\n },\n on: { click: _vm.traktForceSync }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n attrs: { type: \"hidden\", id: \"trakt_pin_url\" },\n domProps: { value: _vm.notifiers.trakt.pinUrl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-email\",\n attrs: { title: \"Email\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://en.wikipedia.org/wiki/Comparison_of_webmail_providers\"\n }\n },\n [_vm._v(\"Email\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Allows configuration of email notifications on a per show basis.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_email\",\n explanations: [\"Send email notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"enabled\", $$v)\n },\n expression: \"notifiers.email.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.email.enabled,\n expression: \"notifiers.email.enabled\"\n }\n ],\n attrs: { id: \"content-use-email\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"email_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"email_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"email_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.email\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.email.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP host\",\n id: \"email_host\",\n explanations: [\n \"hostname of your SMTP email server.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"host\", $$v)\n },\n expression: \"notifiers.email.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n min: 1,\n step: 1,\n label: \"SMTP port\",\n id: \"email_port\",\n explanations: [\n \"port number used to connect to your SMTP host.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.port,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"port\", $$v)\n },\n expression: \"notifiers.email.port\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP from\",\n id: \"email_from\",\n explanations: [\n \"sender email address, some hosts require a real address.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.from,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"from\", $$v)\n },\n expression: \"notifiers.email.from\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Use TLS\",\n id: \"email_tls\",\n explanations: [\"check to use TLS encryption.\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.tls,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"tls\", $$v)\n },\n expression: \"notifiers.email.tls\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP username\",\n id: \"email_username\",\n explanations: [\n \"(optional) your SMTP server username.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.email.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"SMTP password\",\n id: \"email_password\",\n explanations: [\n \"(optional) your SMTP server password.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.email.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_list\",\n label: \"Global email list\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.notifiers.email.addressList\n },\n on: { change: _vm.emailUpdateAddressList }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Email Subject\",\n id: \"email_subject\",\n explanations: [\n \"Use a custom subject for some privacy protection?\",\n \"(Leave blank for the default Medusa subject)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.subject,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"subject\",\n $$v\n )\n },\n expression: \"notifiers.email.subject\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_show\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.emailUpdateShowEmail($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.emailSelectedShowAdresses\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"email\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEmail-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Email\",\n id: \"testEmail\"\n },\n on: { click: _vm.testEmail }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-slack\",\n attrs: { title: \"Slack\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://slack.com\" } },\n [_vm._v(\"Slack\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"Slack is a messaging app for teams.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_slack_client\",\n explanations: [\"Send Slack notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.slack, \"enabled\", $$v)\n },\n expression: \"notifiers.slack.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.slack.enabled,\n expression: \"notifiers.slack.enabled\"\n }\n ],\n attrs: { id: \"content-use-slack-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"slack_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"slack_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"slack_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.slack\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.slack.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Slack Incoming Webhook\",\n id: \"slack_webhook\",\n explanations: [\n \"Create an incoming webhook, to communicate with your slack channel.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.slack.webhook\"\n }\n },\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://my.slack.com/services/new/incoming-webhook\"\n }\n },\n [\n _vm._v(\n \"https://my.slack.com/services/new/incoming-webhook/\"\n )\n ]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testSlack-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Slack\",\n id: \"testSlack\"\n },\n on: { click: _vm.testSlack }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"br\"),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"br\")\n ])\n ]\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clearfix\" })\n ],\n 1\n )\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"label\",\n { staticClass: \"col-sm-2 control-label\", attrs: { for: \"kodi_host\" } },\n [_c(\"span\", [_vm._v(\"KODI IP:Port\")])]\n )\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"clear-left\" }, [\n _c(\"p\", [\n _c(\"b\", [_vm._v(\"Note:\")]),\n _vm._v(\" some Plex Home Theaters \"),\n _c(\"b\", { staticClass: \"boldest\" }, [_vm._v(\"do not\")]),\n _vm._v(\" support notifications e.g. Plexapp for Samsung TVs\")\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }), diff --git a/themes/light/assets/js/medusa-runtime.js b/themes/light/assets/js/medusa-runtime.js index 8669b7baba..087707a721 100644 --- a/themes/light/assets/js/medusa-runtime.js +++ b/themes/light/assets/js/medusa-runtime.js @@ -114,7 +114,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 _api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api.js */ \"./src/api.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.mjs\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./src/components/helpers/index.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n name: 'config-notifications',\n components: {\n AppLink: _helpers__WEBPACK_IMPORTED_MODULE_1__.AppLink,\n ConfigTemplate: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTemplate,\n ConfigTextbox: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextbox,\n ConfigTextboxNumber: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextboxNumber,\n ConfigToggleSlider: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigToggleSlider,\n SelectList: _helpers__WEBPACK_IMPORTED_MODULE_1__.SelectList,\n ShowSelector: _helpers__WEBPACK_IMPORTED_MODULE_1__.ShowSelector\n },\n\n data() {\n return {\n prowlSelectedShow: null,\n prowlSelectedShowApiKeys: [],\n prowlPriorityOptions: [{\n text: 'Very Low',\n value: -2\n }, {\n text: 'Moderate',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverPriorityOptions: [{\n text: 'Lowest',\n value: -2\n }, {\n text: 'Low',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverSoundOptions: [{\n text: 'Default',\n value: 'default'\n }, {\n text: 'Pushover',\n value: 'pushover'\n }, {\n text: 'Bike',\n value: 'bike'\n }, {\n text: 'Bugle',\n value: 'bugle'\n }, {\n text: 'Cash Register',\n value: 'cashregister'\n }, {\n text: 'classical',\n value: 'classical'\n }, {\n text: 'Cosmic',\n value: 'cosmic'\n }, {\n text: 'Falling',\n value: 'falling'\n }, {\n text: 'Gamelan',\n value: 'gamelan'\n }, {\n text: 'Incoming',\n value: 'incoming'\n }, {\n text: 'Intermission',\n value: 'intermission'\n }, {\n text: 'Magic',\n value: 'magic'\n }, {\n text: 'Mechanical',\n value: 'mechanical'\n }, {\n text: 'Piano Bar',\n value: 'pianobar'\n }, {\n text: 'Siren',\n value: 'siren'\n }, {\n text: 'Space Alarm',\n value: 'spacealarm'\n }, {\n text: 'Tug Boat',\n value: 'tugboat'\n }, {\n text: 'Alien Alarm (long)',\n value: 'alien'\n }, {\n text: 'Climb (long)',\n value: 'climb'\n }, {\n text: 'Persistent (long)',\n value: 'persistant'\n }, {\n text: 'Pushover Echo (long)',\n value: 'echo'\n }, {\n text: 'Up Down (long)',\n value: 'updown'\n }, {\n text: 'None (silent)',\n value: 'none'\n }],\n pushbulletDeviceOptions: [{\n text: 'All devices',\n value: ''\n }],\n traktMethodOptions: [{\n text: 'Skip all',\n value: 0\n }, {\n text: 'Download pilot only',\n value: 1\n }, {\n text: 'Get whole show',\n value: 2\n }],\n pushbulletTestInfo: 'Click below to test.',\n joinTestInfo: 'Click below to test.',\n twitterTestInfo: 'Click below to test.',\n twitterKey: '',\n emailSelectedShow: null,\n emailSelectedShowAdresses: [],\n saving: false\n };\n },\n\n computed: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapState)({\n config: state => state.config.general,\n indexers: state => state.config.indexers,\n notifiers: state => state.config.notifiers\n }),\n\n traktNewTokenMessage() {\n const {\n accessToken\n } = this.notifiers.trakt;\n return 'Get ' + accessToken ? 'New ' : 0;\n },\n\n traktIndexersOptions() {\n const {\n indexers\n } = this;\n const {\n traktIndexers\n } = indexers.main;\n const validTraktIndexer = Object.keys(indexers.indexers).filter(k => traktIndexers[k]);\n return validTraktIndexer.map(indexer => {\n return {\n text: indexer,\n value: indexers.indexers[indexer].id\n };\n });\n }\n\n },\n\n beforeMount() {\n // Wait for the next tick, so the component is rendered\n this.$nextTick(() => {\n $('#config-components').tabs();\n });\n },\n\n mounted() {\n // TODO: vueify this.\n $('#trakt_pin').on('keyup change', () => {\n if ($('#trakt_pin').val().length === 0) {\n $('#TraktGetPin').removeClass('hide');\n $('#authTrakt').addClass('hide');\n } else {\n $('#TraktGetPin').addClass('hide');\n $('#authTrakt').removeClass('hide');\n }\n });\n },\n\n methods: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapActions)(['getShows', 'setConfig']),\n\n onChangeProwlApi(items) {\n this.notifiers.prowl.api = items.map(item => item.value);\n },\n\n savePerShowNotifyList(listType, values) {\n const {\n emailSelectedShow,\n prowlSelectedShow\n } = this;\n const form = new FormData();\n\n if (listType === 'prowl') {\n form.set('show', prowlSelectedShow);\n form.set('prowlAPIs', values.map(apiKey => apiKey.value));\n } else {\n form.set('show', emailSelectedShow);\n form.set('emails', values.map(apiKey => apiKey.value));\n } // Save the list\n\n\n _api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute.post('home/saveShowNotifyList', form);\n },\n\n async prowlUpdateApiKeys(selectedShow) {\n this.prowlSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].prowl_notify_list ? response.data[selectedShow].prowl_notify_list.split(',') : [];\n this.prowlSelectedShowApiKeys = selectedShow ? list : [];\n }\n },\n\n async emailUpdateShowEmail(selectedShow) {\n this.emailSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].list ? response.data[selectedShow].list.split(',') : [];\n this.emailSelectedShowAdresses = selectedShow ? list : [];\n }\n },\n\n emailUpdateAddressList(items) {\n this.notifiers.email.addressList = items.map(x => x.value);\n },\n\n async getPushbulletDeviceOptions() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/getPushbulletDevices', {\n params: {\n api: pushbulletApiKey\n }\n });\n const options = [];\n const {\n data\n } = response;\n\n if (!data) {\n return false;\n }\n\n options.push({\n text: 'All devices',\n value: ''\n });\n\n for (const device of data.devices) {\n if (device.active === true) {\n options.push({\n text: device.nickname,\n value: device.iden\n });\n }\n }\n\n this.pushbulletDeviceOptions = options;\n this.pushbulletTestInfo = 'Device list updated. Please choose a device to push to.';\n },\n\n async testPushbulletApi() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testPushbullet', {\n params: {\n api: pushbulletApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.pushbulletTestInfo = data;\n }\n },\n\n async testJoinApi() {\n const {\n api: joinApiKey\n } = this.notifiers.join;\n\n if (!joinApiKey) {\n this.joinTestInfo = 'You didn\\'t supply a Join api key';\n $('#join_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testJoin', {\n params: {\n api: joinApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.joinTestInfo = data;\n }\n },\n\n async twitterStep1() {\n this.twitterTestInfo = MEDUSA.config.layout.loading;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep1');\n const {\n data\n } = response;\n window.open(data);\n this.twitterTestInfo = 'Step1: Confirm Authorization';\n },\n\n async twitterStep2() {\n const twitter = {};\n const {\n twitterKey\n } = this;\n twitter.key = twitterKey;\n\n if (twitter.key) {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep2', {\n params: {\n key: twitter.key\n }\n });\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } else {\n this.twitterTestInfo = 'Please fill out the necessary fields above.';\n }\n },\n\n async twitterTest() {\n try {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testTwitter');\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } catch (error) {\n this.twitterTestInfo = 'Error while trying to request for a test on the twitter api.';\n }\n },\n\n async save() {\n const {\n notifiers,\n setConfig\n } = this; // Disable the save button until we're done.\n\n this.saving = true;\n const section = 'main';\n\n try {\n await setConfig({\n section,\n config: {\n notifiers\n }\n });\n this.$snotify.success('Saved Notifiers config', 'Saved', {\n timeout: 5000\n });\n } catch (error) {\n this.$snotify.error('Error while trying to save notifiers config', 'Error');\n } finally {\n this.saving = false;\n }\n },\n\n testGrowl() {\n const growl = {};\n growl.host = $.trim($('#growl_host').val());\n growl.password = $.trim($('#growl_password').val());\n\n if (!growl.host) {\n $('#testGrowl-result').html('Please fill out the necessary fields above.');\n $('#growl_host').addClass('warning');\n return;\n }\n\n $('#growl_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testGrowl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testGrowl', {\n host: growl.host,\n password: growl.password\n }).done(data => {\n $('#testGrowl-result').html(data);\n $('#testGrowl').prop('disabled', false);\n });\n },\n\n testProwl() {\n const prowl = {};\n prowl.api = $.trim($('#prowl_api').find('input').val());\n prowl.priority = $('#prowl_priority').find('input').val();\n\n if (!prowl.api) {\n $('#testProwl-result').html('Please fill out the necessary fields above.');\n $('#prowl_api').find('input').addClass('warning');\n return;\n }\n\n $('#prowl_api').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testProwl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testProwl', {\n prowl_api: prowl.api,\n // eslint-disable-line camelcase\n prowl_priority: prowl.priority // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testProwl-result').html(data);\n $('#testProwl').prop('disabled', false);\n });\n },\n\n testKODI() {\n const kodi = {};\n const kodiHostInput = $('#kodi_host').find('input');\n const kodiHosts = kodiHostInput.toArray().map(value => value.value).filter(item => item !== '');\n kodi.host = kodiHosts.join(',');\n kodi.username = $.trim($('#kodi_username').val());\n kodi.password = $.trim($('#kodi_password').val());\n\n if (!kodi.host) {\n $('#testKODI-result').html('Please fill out the necessary fields above.');\n $('#kodi_host').find('input').addClass('warning');\n return;\n }\n\n $('#kodi_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testKODI-result').html(MEDUSA.config.layout.loading);\n $.get('home/testKODI', {\n host: kodi.host,\n username: kodi.username,\n password: kodi.password\n }).done(data => {\n $('#testKODI-result').html(data);\n $('#testKODI').prop('disabled', false);\n });\n },\n\n testPHT() {\n const plex = {};\n plex.client = {};\n const plexHostsInput = $('#plex_client_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.client.host = plexHosts.join(',');\n plex.client.username = $.trim($('#plex_client_username').val());\n plex.client.password = $.trim($('#plex_client_password').val());\n\n if (!plex.client.host) {\n $('#testPHT-result').html('Please fill out the necessary fields above.');\n $('#plex_client_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_client_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPHT-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPHT', {\n host: plex.client.host,\n username: plex.client.username,\n password: plex.client.password\n }).done(data => {\n $('#testPHT-result').html(data);\n $('#testPHT').prop('disabled', false);\n });\n },\n\n testPMS() {\n const plex = {};\n plex.server = {};\n const plexHostsInput = $('#plex_server_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.server.host = plexHosts.join(',');\n plex.server.username = $.trim($('#plex_server_username').val());\n plex.server.password = $.trim($('#plex_server_password').val());\n plex.server.token = $.trim($('#plex_server_token').val());\n\n if (!plex.server.host) {\n $('#testPMS-result').html('Please fill out the necessary fields above.');\n $('#plex_server_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_server_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPMS-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPMS', {\n host: plex.server.host,\n username: plex.server.username,\n password: plex.server.password,\n plex_server_token: plex.server.token // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testPMS-result').html(data);\n $('#testPMS').prop('disabled', false);\n });\n },\n\n testEMBY() {\n const emby = {};\n emby.host = $('#emby_host').val();\n emby.apikey = $('#emby_apikey').val();\n\n if (!emby.host || !emby.apikey) {\n $('#testEMBY-result').html('Please fill out the necessary fields above.');\n $('#emby_host').addRemoveWarningClass(emby.host);\n $('#emby_apikey').addRemoveWarningClass(emby.apikey);\n return;\n }\n\n $('#emby_host,#emby_apikey').children('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testEMBY-result').html(MEDUSA.config.layout.loading);\n $.get('home/testEMBY', {\n host: emby.host,\n emby_apikey: emby.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testEMBY-result').html(data);\n $('#testEMBY').prop('disabled', false);\n });\n },\n\n testBoxcar2() {\n const boxcar2 = {};\n boxcar2.accesstoken = $.trim($('#boxcar2_accesstoken').val());\n\n if (!boxcar2.accesstoken) {\n $('#testBoxcar2-result').html('Please fill out the necessary fields above.');\n $('#boxcar2_accesstoken').addClass('warning');\n return;\n }\n\n $('#boxcar2_accesstoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testBoxcar2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testBoxcar2', {\n accesstoken: boxcar2.accesstoken\n }).done(data => {\n $('#testBoxcar2-result').html(data);\n $('#testBoxcar2').prop('disabled', false);\n });\n },\n\n testPushover() {\n const pushover = {};\n pushover.userkey = $('#pushover_userkey').val();\n pushover.apikey = $('#pushover_apikey').val();\n\n if (!pushover.userkey || !pushover.apikey) {\n $('#testPushover-result').html('Please fill out the necessary fields above.');\n $('#pushover_userkey').addRemoveWarningClass(pushover.userkey);\n $('#pushover_apikey').addRemoveWarningClass(pushover.apikey);\n return;\n }\n\n $('#pushover_userkey,#pushover_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushover-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushover', {\n userKey: pushover.userkey,\n apiKey: pushover.apikey\n }).done(data => {\n $('#testPushover-result').html(data);\n $('#testPushover').prop('disabled', false);\n });\n },\n\n testLibnotify() {\n $('#testLibnotify-result').html(MEDUSA.config.layout.loading);\n $.get('home/testLibnotify', data => {\n $('#testLibnotify-result').html(data);\n });\n },\n\n settingsNMJ() {\n const nmj = {};\n nmj.host = $('#nmj_host').val();\n\n if (nmj.host) {\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/settingsNMJ', {\n host: nmj.host\n }, data => {\n if (data === null) {\n $('#nmj_database').removeAttr('readonly');\n $('#nmj_mount').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJ-result').html(JSONData.message);\n $('#nmj_database').val(JSONData.database);\n $('#nmj_mount').val(JSONData.mount);\n\n if (JSONData.database) {\n $('#nmj_database').prop('readonly', true);\n } else {\n $('#nmj_database').removeAttr('readonly');\n }\n\n if (JSONData.mount) {\n $('#nmj_mount').prop('readonly', true);\n } else {\n $('#nmj_mount').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmj_host').focus();\n }\n },\n\n testNMJ() {\n const nmj = {};\n nmj.host = $.trim($('#nmj_host').val());\n nmj.database = $('#nmj_database').val();\n nmj.mount = $('#nmj_mount').val();\n\n if (nmj.host) {\n $('#nmj_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJ', {\n host: nmj.host,\n database: nmj.database,\n mount: nmj.mount\n }).done(data => {\n $('#testNMJ-result').html(data);\n $('#testNMJ').prop('disabled', false);\n });\n } else {\n $('#testNMJ-result').html('Please fill out the necessary fields above.');\n $('#nmj_host').addClass('warning');\n }\n },\n\n settingsNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $('#nmjv2_host').val();\n\n if (nmjv2.host) {\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n nmjv2.dbloc = '';\n const radios = document.getElementsByName('nmjv2_dbloc');\n\n for (let i = 0, len = radios.length; i < len; i++) {\n if (radios[i].checked) {\n nmjv2.dbloc = radios[i].value;\n break;\n }\n }\n\n nmjv2.dbinstance = $('#NMJv2db_instance').val();\n $.get('home/settingsNMJv2', {\n host: nmjv2.host,\n dbloc: nmjv2.dbloc,\n instance: nmjv2.dbinstance\n }, data => {\n if (data === null) {\n $('#nmjv2_database').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJv2-result').html(JSONData.message);\n $('#nmjv2_database').val(JSONData.database);\n\n if (JSONData.database) {\n $('#nmjv2_database').prop('readonly', true);\n } else {\n $('#nmjv2_database').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmjv2_host').focus();\n }\n },\n\n testNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $.trim($('#nmjv2_host').val());\n\n if (nmjv2.host) {\n $('#nmjv2_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJv2', {\n host: nmjv2.host\n }).done(data => {\n $('#testNMJv2-result').html(data);\n $('#testNMJv2').prop('disabled', false);\n });\n } else {\n $('#testNMJv2-result').html('Please fill out the necessary fields above.');\n $('#nmjv2_host').addClass('warning');\n }\n },\n\n testFreeMobile() {\n const freemobile = {};\n freemobile.id = $.trim($('#freemobile_id').val());\n freemobile.apikey = $.trim($('#freemobile_apikey').val());\n\n if (!freemobile.id || !freemobile.apikey) {\n $('#testFreeMobile-result').html('Please fill out the necessary fields above.');\n\n if (freemobile.id) {\n $('#freemobile_id').removeClass('warning');\n } else {\n $('#freemobile_id').addClass('warning');\n }\n\n if (freemobile.apikey) {\n $('#freemobile_apikey').removeClass('warning');\n } else {\n $('#freemobile_apikey').addClass('warning');\n }\n\n return;\n }\n\n $('#freemobile_id,#freemobile_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testFreeMobile-result').html(MEDUSA.config.layout.loading);\n $.get('home/testFreeMobile', {\n freemobile_id: freemobile.id,\n // eslint-disable-line camelcase\n freemobile_apikey: freemobile.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testFreeMobile-result').html(data);\n $('#testFreeMobile').prop('disabled', false);\n });\n },\n\n testTelegram() {\n const telegram = {};\n telegram.id = $.trim($('#telegram_id').val());\n telegram.apikey = $.trim($('#telegram_apikey').val());\n\n if (!telegram.id || !telegram.apikey) {\n $('#testTelegram-result').html('Please fill out the necessary fields above.');\n $('#telegram_id').addRemoveWarningClass(telegram.id);\n $('#telegram_apikey').addRemoveWarningClass(telegram.apikey);\n return;\n }\n\n $('#telegram_id,#telegram_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTelegram-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTelegram', {\n telegram_id: telegram.id,\n // eslint-disable-line camelcase\n telegram_apikey: telegram.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTelegram-result').html(data);\n $('#testTelegram').prop('disabled', false);\n });\n },\n\n testDiscord() {\n const {\n notifiers\n } = this;\n\n if (!notifiers.discord.webhook) {\n $('#testDiscord-result').html('Please fill out the necessary fields above.');\n $('#discord_webhook').addRemoveWarningClass(notifiers.discord.webhook);\n return;\n }\n\n $('#discord_id,#discord_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testDiscord-result').html(MEDUSA.config.layout.loading);\n $.get('home/testDiscord', {\n discord_webhook: notifiers.discord.webhook,\n // eslint-disable-line camelcase\n discord_tts: notifiers.discord.tts // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testDiscord-result').html(data);\n $('#testDiscord').prop('disabled', false);\n });\n },\n\n testSlack() {\n const slack = {};\n slack.webhook = $.trim($('#slack_webhook').val());\n\n if (!slack.webhook) {\n $('#testSlack-result').html('Please fill out the necessary fields above.');\n $('#slack_webhook').addRemoveWarningClass(slack.webhook);\n return;\n }\n\n $('#slack_webhook').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testSlack-result').html(MEDUSA.config.layout.loading);\n $.get('home/testslack', {\n slack_webhook: slack.webhook // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testSlack-result').html(data);\n $('#testSlack').prop('disabled', false);\n });\n },\n\n TraktGetPin() {\n window.open($('#trakt_pin_url').val(), 'popUp', 'toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550');\n $('#trakt_pin').prop('disabled', false);\n },\n\n authTrakt() {\n const trakt = {};\n trakt.pin = $('#trakt_pin').val();\n\n if (trakt.pin.length !== 0) {\n $.get('home/getTraktToken', {\n trakt_pin: trakt.pin // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTrakt-result').html(data);\n $('#authTrakt').addClass('hide');\n $('#trakt_pin').prop('disabled', true);\n $('#trakt_pin').val('');\n $('#TraktGetPin').removeClass('hide');\n });\n }\n },\n\n testTrakt() {\n const trakt = {};\n trakt.username = $.trim($('#trakt_username').val());\n trakt.trendingBlacklist = $.trim($('#trakt_blacklist_name').val());\n\n if (!trakt.username) {\n $('#testTrakt-result').html('Please fill out the necessary fields above.');\n $('#trakt_username').addRemoveWarningClass(trakt.username);\n return;\n }\n\n if (/\\s/g.test(trakt.trendingBlacklist)) {\n $('#testTrakt-result').html('Check blacklist name; the value needs to be a trakt slug');\n $('#trakt_blacklist_name').addClass('warning');\n return;\n }\n\n $('#trakt_username').removeClass('warning');\n $('#trakt_blacklist_name').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTrakt', {\n username: trakt.username,\n blacklist_name: trakt.trendingBlacklist // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTrakt-result').html(data);\n $('#testTrakt').prop('disabled', false);\n });\n },\n\n traktForceSync() {\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.getJSON('home/forceTraktSync', data => {\n $('#testTrakt-result').html(data.result);\n });\n },\n\n testEmail() {\n let to = '';\n const status = $('#testEmail-result');\n status.html(MEDUSA.config.layout.loading);\n let host = $('#email_host').val();\n host = host.length > 0 ? host : null;\n let port = $('#email_port').val();\n port = port.length > 0 ? port : null;\n const tls = $('#email_tls').find('input').is(':checked') ? 1 : 0;\n let from = $('#email_from').val();\n from = from.length > 0 ? from : 'root@localhost';\n const user = $('#email_username').val().trim();\n const pwd = $('#email_password').val();\n let err = '';\n\n if (host === null) {\n err += '
  • You must specify an SMTP hostname!
  • ';\n }\n\n if (port === null) {\n err += '
  • You must specify an SMTP port!
  • ';\n } else if (port.match(/^\\d+$/) === null || Number.parseInt(port, 10) > 65535) {\n err += '
  • SMTP port must be between 0 and 65535!
  • ';\n }\n\n if (err.length > 0) {\n err = '
      ' + err + '
    ';\n status.html(err);\n } else {\n to = prompt('Enter an email address to send the test to:', null); // eslint-disable-line no-alert\n\n if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {\n status.html('

    You must provide a recipient email address!

    ');\n } else {\n $.get('home/testEmail', {\n host,\n port,\n smtp_from: from,\n // eslint-disable-line camelcase\n use_tls: tls,\n // eslint-disable-line camelcase\n user,\n pwd,\n to\n }, msg => {\n $('#testEmail-result').html(msg);\n });\n }\n }\n },\n\n testPushalot() {\n const pushalot = {};\n pushalot.authToken = $.trim($('#pushalot_authorizationtoken').val());\n\n if (!pushalot.authToken) {\n $('#testPushalot-result').html('Please fill out the necessary fields above.');\n $('#pushalot_authorizationtoken').addClass('warning');\n return;\n }\n\n $('#pushalot_authorizationtoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushalot-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushalot', {\n authorizationToken: pushalot.authToken\n }).done(data => {\n $('#testPushalot-result').html(data);\n $('#testPushalot').prop('disabled', false);\n });\n }\n\n }\n});\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-1%5B0%5D.rules%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); +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 _api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api.js */ \"./src/api.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.mjs\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./src/components/helpers/index.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n name: 'config-notifications',\n components: {\n AppLink: _helpers__WEBPACK_IMPORTED_MODULE_1__.AppLink,\n ConfigTemplate: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTemplate,\n ConfigTextbox: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextbox,\n ConfigTextboxNumber: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigTextboxNumber,\n ConfigToggleSlider: _helpers__WEBPACK_IMPORTED_MODULE_1__.ConfigToggleSlider,\n SelectList: _helpers__WEBPACK_IMPORTED_MODULE_1__.SelectList,\n ShowSelector: _helpers__WEBPACK_IMPORTED_MODULE_1__.ShowSelector\n },\n\n data() {\n return {\n prowlSelectedShow: null,\n prowlSelectedShowApiKeys: [],\n prowlPriorityOptions: [{\n text: 'Very Low',\n value: -2\n }, {\n text: 'Moderate',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverPriorityOptions: [{\n text: 'Lowest',\n value: -2\n }, {\n text: 'Low',\n value: -1\n }, {\n text: 'Normal',\n value: 0\n }, {\n text: 'High',\n value: 1\n }, {\n text: 'Emergency',\n value: 2\n }],\n pushoverSoundOptions: [{\n text: 'Default',\n value: 'default'\n }, {\n text: 'Pushover',\n value: 'pushover'\n }, {\n text: 'Bike',\n value: 'bike'\n }, {\n text: 'Bugle',\n value: 'bugle'\n }, {\n text: 'Cash Register',\n value: 'cashregister'\n }, {\n text: 'classical',\n value: 'classical'\n }, {\n text: 'Cosmic',\n value: 'cosmic'\n }, {\n text: 'Falling',\n value: 'falling'\n }, {\n text: 'Gamelan',\n value: 'gamelan'\n }, {\n text: 'Incoming',\n value: 'incoming'\n }, {\n text: 'Intermission',\n value: 'intermission'\n }, {\n text: 'Magic',\n value: 'magic'\n }, {\n text: 'Mechanical',\n value: 'mechanical'\n }, {\n text: 'Piano Bar',\n value: 'pianobar'\n }, {\n text: 'Siren',\n value: 'siren'\n }, {\n text: 'Space Alarm',\n value: 'spacealarm'\n }, {\n text: 'Tug Boat',\n value: 'tugboat'\n }, {\n text: 'Alien Alarm (long)',\n value: 'alien'\n }, {\n text: 'Climb (long)',\n value: 'climb'\n }, {\n text: 'Persistent (long)',\n value: 'persistant'\n }, {\n text: 'Pushover Echo (long)',\n value: 'echo'\n }, {\n text: 'Up Down (long)',\n value: 'updown'\n }, {\n text: 'None (silent)',\n value: 'none'\n }],\n pushbulletDeviceOptions: [{\n text: 'All devices',\n value: ''\n }],\n traktRequestSend: false,\n traktRequestAuthenticated: false,\n traktUserCode: '',\n traktRequestMessage: '',\n traktMethodOptions: [{\n text: 'Skip all',\n value: 0\n }, {\n text: 'Download pilot only',\n value: 1\n }, {\n text: 'Get whole show',\n value: 2\n }],\n pushbulletTestInfo: 'Click below to test.',\n joinTestInfo: 'Click below to test.',\n twitterTestInfo: 'Click below to test.',\n twitterKey: '',\n emailSelectedShow: null,\n emailSelectedShowAdresses: [],\n saving: false\n };\n },\n\n computed: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapState)({\n config: state => state.config.general,\n indexers: state => state.config.indexers,\n notifiers: state => state.config.notifiers\n }),\n\n traktIndexersOptions() {\n const {\n indexers\n } = this;\n const {\n traktIndexers\n } = indexers.main;\n const validTraktIndexer = Object.keys(indexers.indexers).filter(k => traktIndexers[k]);\n return validTraktIndexer.map(indexer => {\n return {\n text: indexer,\n value: indexers.indexers[indexer].id\n };\n });\n }\n\n },\n\n beforeMount() {\n // Wait for the next tick, so the component is rendered\n this.$nextTick(() => {\n $('#config-components').tabs();\n });\n },\n\n mounted() {\n // TODO: vueify this.\n $('#trakt_pin').on('keyup change', () => {\n if ($('#trakt_pin').val().length === 0) {\n $('#TraktGetPin').removeClass('hide');\n $('#authTrakt').addClass('hide');\n } else {\n $('#TraktGetPin').addClass('hide');\n $('#authTrakt').removeClass('hide');\n }\n });\n },\n\n methods: { ...(0,vuex__WEBPACK_IMPORTED_MODULE_2__.mapActions)(['getShows', 'setConfig']),\n\n onChangeProwlApi(items) {\n this.notifiers.prowl.api = items.map(item => item.value);\n },\n\n savePerShowNotifyList(listType, values) {\n const {\n emailSelectedShow,\n prowlSelectedShow\n } = this;\n const form = new FormData();\n\n if (listType === 'prowl') {\n form.set('show', prowlSelectedShow);\n form.set('prowlAPIs', values.map(apiKey => apiKey.value));\n } else {\n form.set('show', emailSelectedShow);\n form.set('emails', values.map(apiKey => apiKey.value));\n } // Save the list\n\n\n _api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute.post('home/saveShowNotifyList', form);\n },\n\n async prowlUpdateApiKeys(selectedShow) {\n this.prowlSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].prowl_notify_list ? response.data[selectedShow].prowl_notify_list.split(',') : [];\n this.prowlSelectedShowApiKeys = selectedShow ? list : [];\n }\n },\n\n async emailUpdateShowEmail(selectedShow) {\n this.emailSelectedShow = selectedShow;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/loadShowNotifyLists');\n\n if (response.data._size > 0) {\n const list = response.data[selectedShow].list ? response.data[selectedShow].list.split(',') : [];\n this.emailSelectedShowAdresses = selectedShow ? list : [];\n }\n },\n\n emailUpdateAddressList(items) {\n this.notifiers.email.addressList = items.map(x => x.value);\n },\n\n async getPushbulletDeviceOptions() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/getPushbulletDevices', {\n params: {\n api: pushbulletApiKey\n }\n });\n const options = [];\n const {\n data\n } = response;\n\n if (!data) {\n return false;\n }\n\n options.push({\n text: 'All devices',\n value: ''\n });\n\n for (const device of data.devices) {\n if (device.active === true) {\n options.push({\n text: device.nickname,\n value: device.iden\n });\n }\n }\n\n this.pushbulletDeviceOptions = options;\n this.pushbulletTestInfo = 'Device list updated. Please choose a device to push to.';\n },\n\n async testPushbulletApi() {\n const {\n api: pushbulletApiKey\n } = this.notifiers.pushbullet;\n\n if (!pushbulletApiKey) {\n this.pushbulletTestInfo = 'You didn\\'t supply a Pushbullet api key';\n $('#pushbullet_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testPushbullet', {\n params: {\n api: pushbulletApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.pushbulletTestInfo = data;\n }\n },\n\n async testJoinApi() {\n const {\n api: joinApiKey\n } = this.notifiers.join;\n\n if (!joinApiKey) {\n this.joinTestInfo = 'You didn\\'t supply a Join api key';\n $('#join_api').find('input').focus();\n return false;\n }\n\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testJoin', {\n params: {\n api: joinApiKey\n }\n });\n const {\n data\n } = response;\n\n if (data) {\n this.joinTestInfo = data;\n }\n },\n\n async twitterStep1() {\n this.twitterTestInfo = MEDUSA.config.layout.loading;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep1');\n const {\n data\n } = response;\n window.open(data);\n this.twitterTestInfo = 'Step1: Confirm Authorization';\n },\n\n async twitterStep2() {\n const twitter = {};\n const {\n twitterKey\n } = this;\n twitter.key = twitterKey;\n\n if (twitter.key) {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/twitterStep2', {\n params: {\n key: twitter.key\n }\n });\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } else {\n this.twitterTestInfo = 'Please fill out the necessary fields above.';\n }\n },\n\n async twitterTest() {\n try {\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/testTwitter');\n const {\n data\n } = response;\n this.twitterTestInfo = data;\n } catch (error) {\n this.twitterTestInfo = 'Error while trying to request for a test on the twitter api.';\n }\n },\n\n async save() {\n const {\n notifiers,\n setConfig\n } = this; // Disable the save button until we're done.\n\n this.saving = true;\n const section = 'main';\n\n try {\n await setConfig({\n section,\n config: {\n notifiers\n }\n });\n this.$snotify.success('Saved Notifiers config', 'Saved', {\n timeout: 5000\n });\n } catch (error) {\n this.$snotify.error('Error while trying to save notifiers config', 'Error');\n } finally {\n this.saving = false;\n }\n },\n\n testGrowl() {\n const growl = {};\n growl.host = $.trim($('#growl_host').val());\n growl.password = $.trim($('#growl_password').val());\n\n if (!growl.host) {\n $('#testGrowl-result').html('Please fill out the necessary fields above.');\n $('#growl_host').addClass('warning');\n return;\n }\n\n $('#growl_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testGrowl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testGrowl', {\n host: growl.host,\n password: growl.password\n }).done(data => {\n $('#testGrowl-result').html(data);\n $('#testGrowl').prop('disabled', false);\n });\n },\n\n testProwl() {\n const prowl = {};\n prowl.api = $.trim($('#prowl_api').find('input').val());\n prowl.priority = $('#prowl_priority').find('input').val();\n\n if (!prowl.api) {\n $('#testProwl-result').html('Please fill out the necessary fields above.');\n $('#prowl_api').find('input').addClass('warning');\n return;\n }\n\n $('#prowl_api').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testProwl-result').html(MEDUSA.config.layout.loading);\n $.get('home/testProwl', {\n prowl_api: prowl.api,\n // eslint-disable-line camelcase\n prowl_priority: prowl.priority // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testProwl-result').html(data);\n $('#testProwl').prop('disabled', false);\n });\n },\n\n testKODI() {\n const kodi = {};\n const kodiHostInput = $('#kodi_host').find('input');\n const kodiHosts = kodiHostInput.toArray().map(value => value.value).filter(item => item !== '');\n kodi.host = kodiHosts.join(',');\n kodi.username = $.trim($('#kodi_username').val());\n kodi.password = $.trim($('#kodi_password').val());\n\n if (!kodi.host) {\n $('#testKODI-result').html('Please fill out the necessary fields above.');\n $('#kodi_host').find('input').addClass('warning');\n return;\n }\n\n $('#kodi_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testKODI-result').html(MEDUSA.config.layout.loading);\n $.get('home/testKODI', {\n host: kodi.host,\n username: kodi.username,\n password: kodi.password\n }).done(data => {\n $('#testKODI-result').html(data);\n $('#testKODI').prop('disabled', false);\n });\n },\n\n testPHT() {\n const plex = {};\n plex.client = {};\n const plexHostsInput = $('#plex_client_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.client.host = plexHosts.join(',');\n plex.client.username = $.trim($('#plex_client_username').val());\n plex.client.password = $.trim($('#plex_client_password').val());\n\n if (!plex.client.host) {\n $('#testPHT-result').html('Please fill out the necessary fields above.');\n $('#plex_client_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_client_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPHT-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPHT', {\n host: plex.client.host,\n username: plex.client.username,\n password: plex.client.password\n }).done(data => {\n $('#testPHT-result').html(data);\n $('#testPHT').prop('disabled', false);\n });\n },\n\n testPMS() {\n const plex = {};\n plex.server = {};\n const plexHostsInput = $('#plex_server_host').find('input');\n const plexHosts = plexHostsInput.toArray().map(value => value.value).filter(item => item !== '');\n plex.server.host = plexHosts.join(',');\n plex.server.username = $.trim($('#plex_server_username').val());\n plex.server.password = $.trim($('#plex_server_password').val());\n plex.server.token = $.trim($('#plex_server_token').val());\n\n if (!plex.server.host) {\n $('#testPMS-result').html('Please fill out the necessary fields above.');\n $('#plex_server_host').find('input').addClass('warning');\n return;\n }\n\n $('#plex_server_host').find('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPMS-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPMS', {\n host: plex.server.host,\n username: plex.server.username,\n password: plex.server.password,\n plex_server_token: plex.server.token // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testPMS-result').html(data);\n $('#testPMS').prop('disabled', false);\n });\n },\n\n testEMBY() {\n const emby = {};\n emby.host = $('#emby_host').val();\n emby.apikey = $('#emby_apikey').val();\n\n if (!emby.host || !emby.apikey) {\n $('#testEMBY-result').html('Please fill out the necessary fields above.');\n $('#emby_host').addRemoveWarningClass(emby.host);\n $('#emby_apikey').addRemoveWarningClass(emby.apikey);\n return;\n }\n\n $('#emby_host,#emby_apikey').children('input').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testEMBY-result').html(MEDUSA.config.layout.loading);\n $.get('home/testEMBY', {\n host: emby.host,\n emby_apikey: emby.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testEMBY-result').html(data);\n $('#testEMBY').prop('disabled', false);\n });\n },\n\n testBoxcar2() {\n const boxcar2 = {};\n boxcar2.accesstoken = $.trim($('#boxcar2_accesstoken').val());\n\n if (!boxcar2.accesstoken) {\n $('#testBoxcar2-result').html('Please fill out the necessary fields above.');\n $('#boxcar2_accesstoken').addClass('warning');\n return;\n }\n\n $('#boxcar2_accesstoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testBoxcar2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testBoxcar2', {\n accesstoken: boxcar2.accesstoken\n }).done(data => {\n $('#testBoxcar2-result').html(data);\n $('#testBoxcar2').prop('disabled', false);\n });\n },\n\n testPushover() {\n const pushover = {};\n pushover.userkey = $('#pushover_userkey').val();\n pushover.apikey = $('#pushover_apikey').val();\n\n if (!pushover.userkey || !pushover.apikey) {\n $('#testPushover-result').html('Please fill out the necessary fields above.');\n $('#pushover_userkey').addRemoveWarningClass(pushover.userkey);\n $('#pushover_apikey').addRemoveWarningClass(pushover.apikey);\n return;\n }\n\n $('#pushover_userkey,#pushover_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushover-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushover', {\n userKey: pushover.userkey,\n apiKey: pushover.apikey\n }).done(data => {\n $('#testPushover-result').html(data);\n $('#testPushover').prop('disabled', false);\n });\n },\n\n testLibnotify() {\n $('#testLibnotify-result').html(MEDUSA.config.layout.loading);\n $.get('home/testLibnotify', data => {\n $('#testLibnotify-result').html(data);\n });\n },\n\n settingsNMJ() {\n const nmj = {};\n nmj.host = $('#nmj_host').val();\n\n if (nmj.host) {\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/settingsNMJ', {\n host: nmj.host\n }, data => {\n if (data === null) {\n $('#nmj_database').removeAttr('readonly');\n $('#nmj_mount').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJ-result').html(JSONData.message);\n $('#nmj_database').val(JSONData.database);\n $('#nmj_mount').val(JSONData.mount);\n\n if (JSONData.database) {\n $('#nmj_database').prop('readonly', true);\n } else {\n $('#nmj_database').removeAttr('readonly');\n }\n\n if (JSONData.mount) {\n $('#nmj_mount').prop('readonly', true);\n } else {\n $('#nmj_mount').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmj_host').focus();\n }\n },\n\n testNMJ() {\n const nmj = {};\n nmj.host = $.trim($('#nmj_host').val());\n nmj.database = $('#nmj_database').val();\n nmj.mount = $('#nmj_mount').val();\n\n if (nmj.host) {\n $('#nmj_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJ-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJ', {\n host: nmj.host,\n database: nmj.database,\n mount: nmj.mount\n }).done(data => {\n $('#testNMJ-result').html(data);\n $('#testNMJ').prop('disabled', false);\n });\n } else {\n $('#testNMJ-result').html('Please fill out the necessary fields above.');\n $('#nmj_host').addClass('warning');\n }\n },\n\n settingsNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $('#nmjv2_host').val();\n\n if (nmjv2.host) {\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n nmjv2.dbloc = '';\n const radios = document.getElementsByName('nmjv2_dbloc');\n\n for (let i = 0, len = radios.length; i < len; i++) {\n if (radios[i].checked) {\n nmjv2.dbloc = radios[i].value;\n break;\n }\n }\n\n nmjv2.dbinstance = $('#NMJv2db_instance').val();\n $.get('home/settingsNMJv2', {\n host: nmjv2.host,\n dbloc: nmjv2.dbloc,\n instance: nmjv2.dbinstance\n }, data => {\n if (data === null) {\n $('#nmjv2_database').removeAttr('readonly');\n }\n\n const JSONData = $.parseJSON(data);\n $('#testNMJv2-result').html(JSONData.message);\n $('#nmjv2_database').val(JSONData.database);\n\n if (JSONData.database) {\n $('#nmjv2_database').prop('readonly', true);\n } else {\n $('#nmjv2_database').removeAttr('readonly');\n }\n });\n } else {\n alert('Please fill in the Popcorn IP address'); // eslint-disable-line no-alert\n\n $('#nmjv2_host').focus();\n }\n },\n\n testNMJv2() {\n const nmjv2 = {};\n nmjv2.host = $.trim($('#nmjv2_host').val());\n\n if (nmjv2.host) {\n $('#nmjv2_host').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testNMJv2-result').html(MEDUSA.config.layout.loading);\n $.get('home/testNMJv2', {\n host: nmjv2.host\n }).done(data => {\n $('#testNMJv2-result').html(data);\n $('#testNMJv2').prop('disabled', false);\n });\n } else {\n $('#testNMJv2-result').html('Please fill out the necessary fields above.');\n $('#nmjv2_host').addClass('warning');\n }\n },\n\n testFreeMobile() {\n const freemobile = {};\n freemobile.id = $.trim($('#freemobile_id').val());\n freemobile.apikey = $.trim($('#freemobile_apikey').val());\n\n if (!freemobile.id || !freemobile.apikey) {\n $('#testFreeMobile-result').html('Please fill out the necessary fields above.');\n\n if (freemobile.id) {\n $('#freemobile_id').removeClass('warning');\n } else {\n $('#freemobile_id').addClass('warning');\n }\n\n if (freemobile.apikey) {\n $('#freemobile_apikey').removeClass('warning');\n } else {\n $('#freemobile_apikey').addClass('warning');\n }\n\n return;\n }\n\n $('#freemobile_id,#freemobile_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testFreeMobile-result').html(MEDUSA.config.layout.loading);\n $.get('home/testFreeMobile', {\n freemobile_id: freemobile.id,\n // eslint-disable-line camelcase\n freemobile_apikey: freemobile.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testFreeMobile-result').html(data);\n $('#testFreeMobile').prop('disabled', false);\n });\n },\n\n testTelegram() {\n const telegram = {};\n telegram.id = $.trim($('#telegram_id').val());\n telegram.apikey = $.trim($('#telegram_apikey').val());\n\n if (!telegram.id || !telegram.apikey) {\n $('#testTelegram-result').html('Please fill out the necessary fields above.');\n $('#telegram_id').addRemoveWarningClass(telegram.id);\n $('#telegram_apikey').addRemoveWarningClass(telegram.apikey);\n return;\n }\n\n $('#telegram_id,#telegram_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testTelegram-result').html(MEDUSA.config.layout.loading);\n $.get('home/testTelegram', {\n telegram_id: telegram.id,\n // eslint-disable-line camelcase\n telegram_apikey: telegram.apikey // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testTelegram-result').html(data);\n $('#testTelegram').prop('disabled', false);\n });\n },\n\n testDiscord() {\n const {\n notifiers\n } = this;\n\n if (!notifiers.discord.webhook) {\n $('#testDiscord-result').html('Please fill out the necessary fields above.');\n $('#discord_webhook').addRemoveWarningClass(notifiers.discord.webhook);\n return;\n }\n\n $('#discord_id,#discord_apikey').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testDiscord-result').html(MEDUSA.config.layout.loading);\n $.get('home/testDiscord', {\n discord_webhook: notifiers.discord.webhook,\n // eslint-disable-line camelcase\n discord_tts: notifiers.discord.tts // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testDiscord-result').html(data);\n $('#testDiscord').prop('disabled', false);\n });\n },\n\n testSlack() {\n const slack = {};\n slack.webhook = $.trim($('#slack_webhook').val());\n\n if (!slack.webhook) {\n $('#testSlack-result').html('Please fill out the necessary fields above.');\n $('#slack_webhook').addRemoveWarningClass(slack.webhook);\n return;\n }\n\n $('#slack_webhook').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testSlack-result').html(MEDUSA.config.layout.loading);\n $.get('home/testslack', {\n slack_webhook: slack.webhook // eslint-disable-line camelcase\n\n }).done(data => {\n $('#testSlack-result').html(data);\n $('#testSlack').prop('disabled', false);\n });\n },\n\n async TraktRequestDeviceCode() {\n this.traktUserCode = '';\n this.traktRequestAuthenticated = false;\n const response = await (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/requestTraktDeviceCodeOauth');\n\n if (response.data) {\n this.traktVerificationUrl = response.data.verification_url;\n window.open(response.data.verification_url, 'popUp', 'toolbar=no, scrollbars=no, resizable=no, top=200, left=200, width=650, height=550');\n this.traktRequestSend = true;\n this.traktUserCode = response.data.user_code;\n this.checkTraktAuthenticated();\n }\n },\n\n checkTraktAuthenticated() {\n let counter = 0;\n const i = setInterval(() => {\n (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)('home/checkTrakTokenOauth').then(response => {\n if (response.data) {\n this.traktRequestMessage = response.data.result;\n\n if (!response.data.error) {\n clearInterval(i);\n this.traktRequestAuthenticated = true;\n this.traktUserCode = '';\n }\n }\n });\n counter++;\n\n if (counter === 12) {\n clearInterval(i);\n this.traktRequestAuthenticated = false;\n this.traktUserCode = '';\n }\n }, 5000);\n },\n\n testTrakt() {\n const trakt = {};\n trakt.trendingBlacklist = $.trim($('#trakt_blacklist_name').val());\n\n if (/\\s/g.test(trakt.trendingBlacklist)) {\n $('#testTrakt-result').html('Check blacklist name; the value needs to be a trakt slug');\n $('#trakt_blacklist_name').addClass('warning');\n return;\n }\n\n $('#trakt_blacklist_name').removeClass('warning');\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n (0,_api_js__WEBPACK_IMPORTED_MODULE_0__.apiRoute)(`home/testTrakt?blacklist_name=${trakt.trendingBlacklist}`).then(result => {\n $('#testTrakt-result').html(result.data);\n $('#testTrakt').prop('disabled', false);\n });\n },\n\n traktForceSync() {\n $('#testTrakt-result').html(MEDUSA.config.layout.loading);\n $.getJSON('home/forceTraktSync', data => {\n $('#testTrakt-result').html(data.result);\n });\n },\n\n testEmail() {\n let to = '';\n const status = $('#testEmail-result');\n status.html(MEDUSA.config.layout.loading);\n let host = $('#email_host').val();\n host = host.length > 0 ? host : null;\n let port = $('#email_port').val();\n port = port.length > 0 ? port : null;\n const tls = $('#email_tls').find('input').is(':checked') ? 1 : 0;\n let from = $('#email_from').val();\n from = from.length > 0 ? from : 'root@localhost';\n const user = $('#email_username').val().trim();\n const pwd = $('#email_password').val();\n let err = '';\n\n if (host === null) {\n err += '
  • You must specify an SMTP hostname!
  • ';\n }\n\n if (port === null) {\n err += '
  • You must specify an SMTP port!
  • ';\n } else if (port.match(/^\\d+$/) === null || Number.parseInt(port, 10) > 65535) {\n err += '
  • SMTP port must be between 0 and 65535!
  • ';\n }\n\n if (err.length > 0) {\n err = '
      ' + err + '
    ';\n status.html(err);\n } else {\n to = prompt('Enter an email address to send the test to:', null); // eslint-disable-line no-alert\n\n if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {\n status.html('

    You must provide a recipient email address!

    ');\n } else {\n $.get('home/testEmail', {\n host,\n port,\n smtp_from: from,\n // eslint-disable-line camelcase\n use_tls: tls,\n // eslint-disable-line camelcase\n user,\n pwd,\n to\n }, msg => {\n $('#testEmail-result').html(msg);\n });\n }\n }\n },\n\n testPushalot() {\n const pushalot = {};\n pushalot.authToken = $.trim($('#pushalot_authorizationtoken').val());\n\n if (!pushalot.authToken) {\n $('#testPushalot-result').html('Please fill out the necessary fields above.');\n $('#pushalot_authorizationtoken').addClass('warning');\n return;\n }\n\n $('#pushalot_authorizationtoken').removeClass('warning');\n $(this).prop('disabled', true);\n $('#testPushalot-result').html(MEDUSA.config.layout.loading);\n $.get('home/testPushalot', {\n authorizationToken: pushalot.authToken\n }).done(data => {\n $('#testPushalot-result').html(data);\n $('#testPushalot').prop('disabled', false);\n });\n }\n\n }\n});\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-1%5B0%5D.rules%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }), @@ -4439,7 +4439,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 */ \"render\": () => /* binding */ render,\n/* harmony export */ \"staticRenderFns\": () => /* binding */ staticRenderFns\n/* harmony export */ });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"config-notifications\" } },\n [\n _c(\"vue-snotify\"),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"config\" } }, [\n _c(\"div\", { attrs: { id: \"config-content\" } }, [\n _c(\n \"form\",\n {\n attrs: { id: \"configForm\", method: \"post\" },\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.save()\n }\n }\n },\n [\n _c(\"div\", { attrs: { id: \"config-components\" } }, [\n _c(\"ul\", [\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#home-theater-nas\" } }, [\n _vm._v(\"Home Theater / NAS\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#devices\" } }, [\n _vm._v(\"Devices\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#social\" } }, [\n _vm._v(\"Social\")\n ])\n ],\n 1\n )\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"home-theater-nas\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-kodi\",\n attrs: { title: \"KODI\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://kodi.tv\" } },\n [_vm._v(\"KODI\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A free and open source cross-platform media center and home entertainment system software with a 10-foot user interface designed for the living-room TV.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_kodi\",\n explanations: [\"Send KODI commands?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.kodi, \"enabled\", $$v)\n },\n expression: \"notifiers.kodi.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.kodi.enabled,\n expression: \"notifiers.kodi.enabled\"\n }\n ],\n attrs: { id: \"content-use-kodi\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Always on\",\n id: \"kodi_always_on\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.alwaysOn,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"alwaysOn\",\n $$v\n )\n },\n expression: \"notifiers.kodi.alwaysOn\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"kodi_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"kodi_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"kodi_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.kodi.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.kodi.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update library\",\n id: \"kodi_update_library\",\n explanations: [\n \"update KODI library when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.library,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"library\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.library\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Full library update\",\n id: \"kodi_update_full\",\n explanations: [\n \"perform a full library update if update per-show fails?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.full,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"full\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.full\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Clean library\",\n id: \"kodi_clean_library\",\n explanations: [\n \"clean KODI library when replaces a already downloaded episode?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.cleanLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"cleanLibrary\",\n $$v\n )\n },\n expression: \"notifiers.kodi.cleanLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Only update first host\",\n id: \"kodi_update_onlyfirst\",\n explanations: [\n \"only send library updates/clean to the first active host?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.onlyFirst,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"onlyFirst\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.onlyFirst\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"col-sm-10 content\" },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"kodi_host\",\n id: \"kodi_host\",\n \"list-items\": _vm.notifiers.kodi.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.kodi.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"host running KODI (eg. 192.168.1.100:8080)\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"kodi_username\",\n explanations: [\n \"username for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.kodi.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"kodi_password\",\n explanations: [\n \"password for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.kodi.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testKODI-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test KODI\",\n id: \"testKODI\"\n },\n on: { click: _vm.testKODI }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plex\",\n attrs: { title: \"Plex Media Server\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Media Server\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Experience your media on a visually stunning, easy to use interface on your Mac connected to your TV. Your media library has never looked this good!\"\n )\n ]),\n _vm._v(\" \"),\n _vm.notifiers.plex.server.enabled\n ? _c(\"p\", { staticClass: \"plexinfo\" }, [\n _vm._v(\n \"For sending notifications to Plex Home Theater (PHT) clients, use the KODI notifier with port \"\n ),\n _c(\"b\", [_vm._v(\"3005\")]),\n _vm._v(\".\")\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_server\",\n explanations: [\"Send Plex server notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.server.enabled,\n expression: \"notifiers.plex.server.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-server\" }\n },\n [\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Plex Media Server Auth Token\",\n id: \"plex_server_token\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.token,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"token\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.token\"\n }\n },\n [\n _c(\"p\", [_vm._v(\"Auth Token used by plex\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\n \"span\",\n [\n _vm._v(\"See: \"),\n _c(\n \"app-link\",\n {\n staticClass: \"wiki\",\n attrs: {\n href:\n \"https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token\"\n }\n },\n [\n _c(\"strong\", [\n _vm._v(\n \"Finding your account token\"\n )\n ])\n ]\n )\n ],\n 1\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_server_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_server_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update Library\",\n id: \"plex_update_library\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.server.updateLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"updateLibrary\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.server.updateLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_server_host\",\n label: \"Plex Media Server IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_server_host\",\n id: \"plex_server_host\",\n \"list-items\":\n _vm.notifiers.plex.server.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.server.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Media Server\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.1:32400, 192.168.1.2:32400)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"plex_server_https\",\n explanations: [\n \"use https for plex media server requests?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.https,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"https\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.https\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPMS-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Media Server(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Media Server\",\n id: \"testPMS\"\n },\n on: { click: _vm.testPMS }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clear-left\" }, [\n _vm._v(\" \")\n ])\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plexth\",\n attrs: { title: \"Plex Media Client\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Home Theater\")]\n )\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_client\",\n explanations: [\n \"Send Plex Home Theater notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.client.enabled,\n expression: \"notifiers.plex.client.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"plex_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"plex_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"plex_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_client_host\",\n label: \"Plex Home Theater IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_client_host\",\n id: \"plex_client_host\",\n \"list-items\":\n _vm.notifiers.plex.client.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.client.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Home Theater\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.100:3000, 192.168.1.101:3000)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_client_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_client_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPHT-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Home Theater(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Home Theater\",\n id: \"testPHT\"\n },\n on: { click: _vm.testPHT }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _vm._m(1)\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-emby\",\n attrs: { title: \"Emby\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://emby.media\" } },\n [_vm._v(\"Emby\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A home media server built using other popular open source technologies.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_emby\",\n explanations: [\"Send update commands to Emby?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"enabled\", $$v)\n },\n expression: \"notifiers.emby.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.emby.enabled,\n expression: \"notifiers.emby.enabled\"\n }\n ],\n attrs: { id: \"content_use_emby\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Emby IP:Port\",\n id: \"emby_host\",\n explanations: [\n \"host running Emby (eg. 192.168.1.100:8096)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"host\", $$v)\n },\n expression: \"notifiers.emby.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: { label: \"Api Key\", id: \"emby_apikey\" },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.apiKey,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"apiKey\", $$v)\n },\n expression: \"notifiers.emby.apiKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEMBY-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Emby\",\n id: \"testEMBY\"\n },\n on: { click: _vm.testEMBY }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJ\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmj\",\n explanations: [\"Send update commands to NMJ?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"enabled\", $$v)\n },\n expression: \"notifiers.nmj.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmj.enabled,\n expression: \"notifiers.nmj.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmj\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmj_host\",\n explanations: [\n \"IP address of Popcorn 200-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"host\", $$v)\n },\n expression: \"notifiers.nmj.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"settingsNMJ\",\n label: \"Get settings\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Get Settings\",\n id: \"settingsNMJ\"\n },\n on: { click: _vm.settingsNMJ }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on and NMJ running.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ database\",\n id: \"nmj_database\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.database,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"database\", $$v)\n },\n expression: \"notifiers.nmj.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ mount\",\n id: \"nmj_mount\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.mount,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"mount\", $$v)\n },\n expression: \"notifiers.nmj.mount\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJ-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJ\",\n id: \"testNMJ\"\n },\n on: { click: _vm.testNMJ }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox v2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJv2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJv2, is the official media jukebox interface made available for the Popcorn Hour 300 & 400-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmjv2\",\n explanations: [\n \"Send popcorn hour (nmjv2) notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"enabled\", $$v)\n },\n expression: \"notifiers.nmjv2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmjv2.enabled,\n expression: \"notifiers.nmjv2.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmjv2\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmjv2_host\",\n explanations: [\n \"IP address of Popcorn 300/400-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"host\", $$v)\n },\n expression: \"notifiers.nmjv2.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_location\",\n label: \"Database location\"\n }\n },\n [\n _c(\n \"label\",\n {\n staticClass: \"space-right\",\n attrs: { for: \"NMJV2_DBLOC_A\" }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"local\",\n id: \"NMJV2_DBLOC_A\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Local Media\\n \"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"label\",\n { attrs: { for: \"NMJV2_DBLOC_B\" } },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"network\",\n id: \"NMJV2_DBLOC_B\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Network Media\\n \"\n )\n ]\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_instance\",\n label: \"Database instance\"\n }\n },\n [\n _c(\n \"select\",\n {\n staticClass: \"form-control input-sm\",\n attrs: { id: \"NMJv2db_instance\" }\n },\n [\n _c(\"option\", { attrs: { value: \"0\" } }, [\n _vm._v(\"#1 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"1\" } }, [\n _vm._v(\"#2 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"2\" } }, [\n _vm._v(\"#3 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"3\" } }, [\n _vm._v(\"#4 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"4\" } }, [\n _vm._v(\"#5 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"5\" } }, [\n _vm._v(\"#6 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"6\" } }, [\n _vm._v(\"#7 \")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"adjust this value if the wrong database is selected.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"get_nmjv2_find_database\",\n label: \"Find database\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Find Database\",\n id: \"settingsNMJv2\"\n },\n on: { click: _vm.settingsNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJv2 database\",\n id: \"nmjv2_database\",\n explanations: [\n \"automatically filled via the 'Find Database' buttons.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.database,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.nmjv2,\n \"database\",\n $$v\n )\n },\n expression: \"notifiers.nmjv2.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJv2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJv2\",\n id: \"testNMJv2\"\n },\n on: { click: _vm.testNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno1\",\n attrs: { title: \"Synology\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"The Synology DiskStation NAS.\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Indexer is the daemon running on the Synology NAS to build its media database.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"use_synoindex\",\n explanations: [\n \"Note: requires Medusa to be running on your Synology NAS.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synologyIndex.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synologyIndex,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.synologyIndex.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synologyIndex.enabled,\n expression: \"notifiers.synologyIndex.enabled\"\n }\n ],\n attrs: { id: \"content_use_synoindex\" }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ]\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno2\",\n attrs: { title: \"Synology Indexer\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology Notifier\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Notifier is the notification system of Synology DSM\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_synologynotifier\",\n explanations: [\n \"Send notifications to the Synology Notifier?\",\n \"Note: requires Medusa to be running on your Synology DSM.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.synology, \"enabled\", $$v)\n },\n expression: \"notifiers.synology.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synology.enabled,\n expression: \"notifiers.synology.enabled\"\n }\n ],\n attrs: { id: \"content-use-synology-notifier\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"synology_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"synology_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pytivo\",\n attrs: { title: \"pyTivo\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://pytivo.sourceforge.net/wiki/index.php/PyTivo\"\n }\n },\n [_vm._v(\"pyTivo\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pytivo\",\n explanations: [\"Send notifications to pyTivo?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"enabled\", $$v)\n },\n expression: \"notifiers.pyTivo.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pyTivo.enabled,\n expression: \"notifiers.pyTivo.enabled\"\n }\n ],\n attrs: { id: \"content-use-pytivo\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo IP:Port\",\n id: \"pytivo_host\",\n explanations: [\n \"host running pyTivo (eg. 192.168.1.1:9032)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"host\", $$v)\n },\n expression: \"notifiers.pyTivo.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo share name\",\n id: \"pytivo_name\",\n explanations: [\n \"(Messages & Settings > Account & System Information > System Information > DVR name)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.shareName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pyTivo,\n \"shareName\",\n $$v\n )\n },\n expression: \"notifiers.pyTivo.shareName\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Tivo name\",\n id: \"pytivo_tivo_name\",\n explanations: [\n \"value used in pyTivo Web Configuration to name the share.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"name\", $$v)\n },\n expression: \"notifiers.pyTivo.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"devices\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-growl\",\n attrs: { title: \"Growl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://growl.info/\" } },\n [_vm._v(\"Growl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A cross-platform unobtrusive global notification system.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_growl_client\",\n explanations: [\"Send Growl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"enabled\", $$v)\n },\n expression: \"notifiers.growl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.growl.enabled,\n expression: \"notifiers.growl.enabled\"\n }\n ],\n attrs: { id: \"content-use-growl-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"growl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"growl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"growl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.growl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.growl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Growl IP:Port\",\n id: \"growl_host\",\n explanations: [\n \"host running Growl (eg. 192.168.1.100:23053)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"host\", $$v)\n },\n expression: \"notifiers.growl.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"growl_password\",\n explanations: [\n \"may leave blank if Medusa is on the same host.\",\n \"otherwise Growl requires a password to be used.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.growl.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testGrowl-result\" }\n },\n [\n _vm._v(\n \"Click below to register and test Growl, this is required for Growl notifications to work.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Register Growl\",\n id: \"testGrowl\"\n },\n on: { click: _vm.testGrowl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-prowl\",\n attrs: { title: \"Prowl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://www.prowlapp.com/\" } },\n [_vm._v(\"Prowl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"A Growl client for iOS.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_prowl\",\n explanations: [\"Send Prowl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.prowl, \"enabled\", $$v)\n },\n expression: \"notifiers.prowl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.prowl.enabled,\n expression: \"notifiers.prowl.enabled\"\n }\n ],\n attrs: { id: \"content-use-prowl\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"prowl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"prowl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"prowl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.prowl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.prowl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Prowl Message Title\",\n id: \"prowl_message_title\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.messageTitle,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"messageTitle\",\n $$v\n )\n },\n expression: \"notifiers.prowl.messageTitle\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_api\",\n label: \"Api\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl_api\",\n id: \"prowl_api\",\n \"csv-enabled\": \"\",\n \"list-items\": _vm.notifiers.prowl.api\n },\n on: { change: _vm.onChangeProwlApi }\n }),\n _vm._v(\" \"),\n _c(\n \"span\",\n [\n _vm._v(\n \"Prowl API(s) listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\n \" shows.\\n Your Prowl API key is available at:\\n \"\n ),\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://www.prowlapp.com/api_settings.php\"\n }\n },\n [\n _vm._v(\n \"\\n https://www.prowlapp.com/api_settings.php\"\n )\n ]\n ),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_show_notification_list\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.prowlUpdateApiKeys($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl-show-list\",\n id: \"prowl-show-list\",\n \"list-items\":\n _vm.prowlSelectedShowApiKeys\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"prowl\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Configure per-show notifications here by entering Prowl API key(s), after selecting a show in the drop-down box.\\n Be sure to activate the 'Save for this show' button below after each entry.\\n \"\n ),\n _c(\"span\", [\n _vm._v(\n \"The values are automatically saved when adding the api key.\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_priority\",\n label: \"Prowl priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.prowl.priority,\n expression: \"notifiers.prowl.priority\"\n }\n ],\n staticClass: \"form-control input-sm\",\n attrs: {\n id: \"prowl_priority\",\n name: \"prowl_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.prowl,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.prowlPriorityOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Prowl messages from Medusa.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testProwl-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Prowl\",\n id: \"testProwl\"\n },\n on: { click: _vm.testProwl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-libnotify\",\n attrs: { title: \"Libnotify\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://library.gnome.org/devel/libnotify/\"\n }\n },\n [_vm._v(\"Libnotify\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"p\",\n [\n _vm._v(\n \"The standard desktop notification API for Linux/*nix systems. This notifier will only function if the pynotify module is installed (Ubuntu/Debian package \"\n ),\n _c(\n \"app-link\",\n { attrs: { href: \"apt:python-notify\" } },\n [_vm._v(\"python-notify\")]\n ),\n _vm._v(\").\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_libnotify_client\",\n explanations: [\"Send Libnotify notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.libnotify.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.libnotify.enabled,\n expression: \"notifiers.libnotify.enabled\"\n }\n ],\n attrs: { id: \"content-use-libnotify\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"libnotify_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"libnotify_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"libnotify_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testLibnotify-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Libnotify\",\n id: \"testLibnotify\"\n },\n on: { click: _vm.testLibnotify }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushover\",\n attrs: { title: \"Pushover\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushover.net/\" } },\n [_vm._v(\"Pushover\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushover makes it easy to send real-time notifications to your Android and iOS devices.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushover_client\",\n explanations: [\"Send Pushover notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushover, \"enabled\", $$v)\n },\n expression: \"notifiers.pushover.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushover.enabled,\n expression: \"notifiers.pushover.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushover\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushover_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushover_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushover_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushover User Key\",\n id: \"pushover_userkey\",\n explanations: [\n \"User Key of your Pushover account\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.userKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"userKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.userKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Pushover API Key\",\n id: \"pushover_apikey\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.apiKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"apiKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.apiKey\"\n }\n },\n [\n _c(\n \"span\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://pushover.net/apps/build/\"\n }\n },\n [_c(\"b\", [_vm._v(\"Click here\")])]\n ),\n _vm._v(\" to create a Pushover API key\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_device\",\n label: \"Pushover Devices\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"pushover_device\",\n id: \"pushover_device\",\n \"list-items\":\n _vm.notifiers.pushover.device\n },\n on: {\n change: function($event) {\n _vm.notifiers.pushover.device = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"List of pushover devices you want to send notifications to\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_sound\",\n label: \"Pushover notification sound\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.pushover.sound,\n expression: \"notifiers.pushover.sound\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_sound\",\n name: \"pushover_sound\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"sound\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.pushoverSoundOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"Choose notification sound to use\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_priority\",\n label: \"Pushover notification priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushover.priority,\n expression:\n \"notifiers.pushover.priority\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_priority\",\n name: \"pushover_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushoverPriorityOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Pushover messages from Medusa\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushover-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushover\",\n id: \"testPushover\"\n },\n on: { click: _vm.testPushover }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-boxcar2\",\n attrs: { title: \"Boxcar 2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://new.boxcar.io/\" } },\n [_vm._v(\"Boxcar 2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Read your messages where and when you want them!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_boxcar2\",\n explanations: [\"Send boxcar2 notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.boxcar2, \"enabled\", $$v)\n },\n expression: \"notifiers.boxcar2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.boxcar2.enabled,\n expression: \"notifiers.boxcar2.enabled\"\n }\n ],\n attrs: { id: \"content-use-boxcar2-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"boxcar2_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"boxcar2_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"boxcar2_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.boxcar2\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Boxcar2 Access token\",\n id: \"boxcar2_accesstoken\",\n explanations: [\n \"access token for your Boxcar account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.accessToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"accessToken\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.accessToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testBoxcar2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Boxcar\",\n id: \"testBoxcar2\"\n },\n on: { click: _vm.testBoxcar2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushalot\",\n attrs: { title: \"Pushalot\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushalot.com\" } },\n [_vm._v(\"Pushalot\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushalot is a platform for receiving custom push notifications to connected devices running Windows Phone or Windows 8.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushalot\",\n explanations: [\"Send Pushalot notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushalot, \"enabled\", $$v)\n },\n expression: \"notifiers.pushalot.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushalot.enabled,\n expression: \"notifiers.pushalot.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushalot-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushalot_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushalot_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushalot_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushalot authorization token\",\n id: \"pushalot_authorizationtoken\",\n explanations: [\n \"authorization token of your Pushalot account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.authToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"authToken\",\n $$v\n )\n },\n expression: \"notifiers.pushalot.authToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushalot-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushalot\",\n id: \"testPushalot\"\n },\n on: { click: _vm.testPushalot }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushbullet\",\n attrs: { title: \"Pushbullet\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.pushbullet.com\" } },\n [_vm._v(\"Pushbullet\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushbullet is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushbullet\",\n explanations: [\"Send pushbullet notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushbullet.enabled,\n expression: \"notifiers.pushbullet.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushbullet-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushbullet_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushbullet_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushbullet_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushbullet API key\",\n id: \"pushbullet_api\",\n explanations: [\n \"API key of your Pushbullet account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushbullet_device_list\",\n label: \"Pushbullet devices\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Update device list\",\n id: \"get-pushbullet-devices\"\n },\n on: {\n click: _vm.getPushbulletDeviceOptions\n }\n }),\n _vm._v(\" \"),\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushbullet.device,\n expression:\n \"notifiers.pushbullet.device\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushbullet_device_list\",\n name: \"pushbullet_device_list\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"device\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushbulletDeviceOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value },\n on: {\n change: function($event) {\n _vm.pushbulletTestInfo =\n \"Don't forget to save your new pushbullet settings.\"\n }\n }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"select device you wish to push to.\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushbullet-resultsfsf\" }\n },\n [_vm._v(_vm._s(_vm.pushbulletTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushbullet\",\n id: \"testPushbullet\"\n },\n on: { click: _vm.testPushbulletApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-join\",\n attrs: { title: \"Join\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://joaoapps.com/join/\" } },\n [_vm._v(\"Join\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Join is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_join\",\n explanations: [\"Send join notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"enabled\", $$v)\n },\n expression: \"notifiers.join.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.join.enabled,\n expression: \"notifiers.join.enabled\"\n }\n ],\n attrs: { id: \"content-use-join-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"join_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"join_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"join_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.join.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.join.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join API key\",\n id: \"join_api\",\n explanations: [\n \"API key of your Join account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"api\", $$v)\n },\n expression: \"notifiers.join.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join Device ID(s) key\",\n id: \"join_device\",\n explanations: [\n \"Enter DeviceID of the device(s) you wish to send notifications to, comma separated if using multiple.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.device,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"device\", $$v)\n },\n expression: \"notifiers.join.device\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testJoin-result\" }\n },\n [_vm._v(_vm._s(_vm.joinTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Join\",\n id: \"testJoin\"\n },\n on: { click: _vm.testJoinApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-freemobile\",\n attrs: { title: \"Free Mobile\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://mobile.free.fr/\" } },\n [_vm._v(\"Free Mobile\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Free Mobile is a famous French cellular network provider. It provides to their customer a free SMS API.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_freemobile\",\n explanations: [\"Send SMS notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.freemobile.enabled,\n expression: \"notifiers.freemobile.enabled\"\n }\n ],\n attrs: { id: \"content-use-freemobile-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"freemobile_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"freemobile_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"freemobile_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile customer ID\",\n id: \"freemobile_id\",\n explanations: [\n \"It's your Free Mobile customer ID (8 digits)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.id,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"id\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile API Key\",\n id: \"freemobile_apikey\",\n explanations: [\n \"Find your API Key in your customer portal.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testFreeMobile-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test SMS\",\n id: \"testFreeMobile\"\n },\n on: { click: _vm.testFreeMobile }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-telegram\",\n attrs: { title: \"Telegram\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://telegram.org/\" } },\n [_vm._v(\"Telegram\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Telegram is a cloud-based instant messaging service.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_telegram\",\n explanations: [\"Send Telegram notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"enabled\", $$v)\n },\n expression: \"notifiers.telegram.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.telegram.enabled,\n expression: \"notifiers.telegram.enabled\"\n }\n ],\n attrs: { id: \"content-use-telegram-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"telegram_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"telegram_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"telegram_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"User/group ID\",\n id: \"telegram_id\",\n explanations: [\n \"Contact @myidbot on Telegram to get an ID\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.id,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"id\", $$v)\n },\n expression: \"notifiers.telegram.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot API token\",\n id: \"telegram_apikey\",\n explanations: [\n \"Contact @BotFather on Telegram to set up one\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"api\", $$v)\n },\n expression: \"notifiers.telegram.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTelegram-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Telegram\",\n id: \"testTelegram\"\n },\n on: { click: _vm.testTelegram }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-discord\",\n attrs: { title: \"Discord\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://discordapp.com/\" } },\n [_vm._v(\"Discord\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Discord is a cloud-based All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone..\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_discord\",\n explanations: [\"Send Discord notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"enabled\", $$v)\n },\n expression: \"notifiers.discord.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.discord.enabled,\n expression: \"notifiers.discord.enabled\"\n }\n ],\n attrs: { id: \"content-use-discord-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"discord_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.discord.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"discord_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"discord_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.discord\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Channel webhook\",\n id: \"discord_webhook\",\n explanations: [\n \"Add a webhook to a channel, use the returned url here\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.discord.webhook\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Text to speech\",\n id: \"discord_tts\",\n explanations: [\n \"Use discord text to speech feature\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.tts,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"tts\", $$v)\n },\n expression: \"notifiers.discord.tts\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot username\",\n id: \"discord_name\",\n explanations: [\n \"Create a username for the Discord Bot to use\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"name\", $$v)\n },\n expression: \"notifiers.discord.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testDiscord-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Discord\",\n id: \"testDiscord\"\n },\n on: { click: _vm.testDiscord }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"social\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-twitter\",\n attrs: { title: \"Twitter\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.twitter.com\" } },\n [_vm._v(\"Twitter\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_twitter\",\n explanations: [\n \"Should Medusa post tweets on Twitter?\",\n \"Note: you may want to use a secondary account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"enabled\", $$v)\n },\n expression: \"notifiers.twitter.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.twitter.enabled,\n expression: \"notifiers.twitter.enabled\"\n }\n ],\n attrs: { id: \"content-use-twitter\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"twitter_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.twitter.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"twitter_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"twitter_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.twitter\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Send direct message\",\n id: \"twitter_usedm\",\n explanations: [\n \"send a notification via Direct Message, not via status update\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.directMessage,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"directMessage\",\n $$v\n )\n },\n expression: \"notifiers.twitter.directMessage\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Send DM to\",\n id: \"twitter_dmto\",\n explanations: [\n \"Twitter account to send Direct Messages to (must follow you)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.dmto,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"dmto\", $$v)\n },\n expression: \"notifiers.twitter.dmto\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep1\",\n label: \"Step 1\"\n }\n },\n [\n _c(\n \"span\",\n { staticStyle: { \"font-size\": \"11px\" } },\n [\n _vm._v(\n 'Click the \"Request Authorization\" button. '\n ),\n _c(\"br\"),\n _vm._v(\n \"This will open a new page containing an auth key. \"\n ),\n _c(\"br\"),\n _vm._v(\n \"Note: if nothing happens check your popup blocker.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Request Authorization\",\n id: \"twitter-step-1\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep1($event)\n }\n }\n })\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep2\",\n label: \"Step 2\"\n }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.twitterKey,\n expression: \"twitterKey\"\n }\n ],\n staticClass:\n \"form-control input-sm max-input350\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n id: \"twitter_key\",\n placeholder:\n \"Enter the key Twitter gave you, and click 'Verify Key'\"\n },\n domProps: { value: _vm.twitterKey },\n on: {\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.twitterKey = $event.target.value\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Verify Key\",\n id: \"twitter-step-2\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep2($event)\n }\n }\n })\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", {\n staticClass: \"testNotification\",\n attrs: { id: \"testTwitter-result\" },\n domProps: {\n innerHTML: _vm._s(_vm.twitterTestInfo)\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Twitter\",\n id: \"testTwitter\"\n },\n on: { click: _vm.twitterTest }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-trakt\",\n attrs: { title: \"Trakt\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://trakt.tv/\" } },\n [_vm._v(\"Trakt\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_trakt\",\n explanations: [\"Send Trakt.tv notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"enabled\", $$v)\n },\n expression: \"notifiers.trakt.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.enabled,\n expression: \"notifiers.trakt.enabled\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"trakt_username\",\n explanations: [\n \"username of your Trakt account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.trakt.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_pin\",\n label: \"Trakt PIN\"\n }\n },\n [\n _c(\"input\", {\n staticClass:\n \"form-control input-sm max-input250\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n name: \"trakt_pin\",\n id: \"trakt_pin\",\n value: \"\",\n disabled: _vm.notifiers.trakt.accessToken\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: _vm.traktNewTokenMessage,\n id: \"TraktGetPin\"\n },\n on: { click: _vm.TraktGetPin }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa hide\",\n attrs: {\n type: \"button\",\n value: \"Authorize Medusa\",\n id: \"authTrakt\"\n },\n on: { click: _vm.authTrakt }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"PIN code to authorize Medusa to access Trakt on your behalf.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n label: \"API Timeout\",\n id: \"trakt_timeout\",\n explanations: [\n \"Seconds to wait for Trakt API to respond. (Use 0 to wait forever)\"\n ]\n },\n model: {\n value: _vm.notifiers.trakt.timeout,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"timeout\",\n $$v\n )\n },\n expression: \"notifiers.trakt.timeout\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Default indexer\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.defaultIndexer,\n expression:\n \"notifiers.trakt.defaultIndexer\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_default_indexer\",\n name: \"trakt_default_indexer\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"defaultIndexer\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktIndexersOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync libraries\",\n id: \"trakt_sync\",\n explanations: [\n \"Sync your Medusa show library with your Trakt collection.\",\n \"Note: Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\",\n \"Kodi detects that the episode was deleted and removes from collection which causes Medusa to re-add it. This causes a loop between Medusa and Kodi adding and deleting the episode.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.sync,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"sync\", $$v)\n },\n expression: \"notifiers.trakt.sync\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.sync,\n expression: \"notifiers.trakt.sync\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove Episodes From Collection\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"Remove an Episode from your Trakt Collection if it is not in your Medusa Library.\",\n \"Note:Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync watchlist\",\n id: \"trakt_sync_watchlist\",\n explanations: [\n \"Sync your Medusa library with your Trakt Watchlist (either Show and Episode).\",\n \"Episode will be added on watch list when wanted or snatched and will be removed when downloaded\",\n \"Note: By design, Trakt automatically removes episodes and/or shows from watchlist as soon you have watched them.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.syncWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"syncWatchlist\",\n $$v\n )\n },\n expression: \"notifiers.trakt.syncWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.syncWatchlist,\n expression:\n \"notifiers.trakt.syncWatchlist\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Watchlist add method\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.methodAdd,\n expression:\n \"notifiers.trakt.methodAdd\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_method_add\",\n name: \"trakt_method_add\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"methodAdd\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktMethodOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"method in which to download episodes for new shows.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove episode\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"remove an episode from your watchlist after it's downloaded.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove series\",\n id: \"trakt_remove_serieslist\",\n explanations: [\n \"remove the whole series from your watchlist after any download.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeSerieslist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeSerieslist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeSerieslist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove watched show\",\n id: \"trakt_remove_show_from_application\",\n explanations: [\n \"remove the show from Medusa if it's ended and completely watched\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt\n .removeShowFromApplication,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeShowFromApplication\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeShowFromApplication\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Start paused\",\n id: \"trakt_start_paused\",\n explanations: [\n \"shows grabbed from your trakt watchlist start paused.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.startPaused,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"startPaused\",\n $$v\n )\n },\n expression: \"notifiers.trakt.startPaused\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Trakt blackList name\",\n id: \"trakt_blacklist_name\",\n explanations: [\n \"Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' & 'Add Recommended Shows' pages\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.blacklistName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"blacklistName\",\n $$v\n )\n },\n expression: \"notifiers.trakt.blacklistName\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTrakt-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Trakt\",\n id: \"testTrakt\"\n },\n on: { click: _vm.testTrakt }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Force Sync\",\n id: \"forceSync\"\n },\n on: { click: _vm.traktForceSync }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n attrs: { type: \"hidden\", id: \"trakt_pin_url\" },\n domProps: { value: _vm.notifiers.trakt.pinUrl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-email\",\n attrs: { title: \"Email\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://en.wikipedia.org/wiki/Comparison_of_webmail_providers\"\n }\n },\n [_vm._v(\"Email\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Allows configuration of email notifications on a per show basis.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_email\",\n explanations: [\"Send email notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"enabled\", $$v)\n },\n expression: \"notifiers.email.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.email.enabled,\n expression: \"notifiers.email.enabled\"\n }\n ],\n attrs: { id: \"content-use-email\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"email_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"email_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"email_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.email\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.email.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP host\",\n id: \"email_host\",\n explanations: [\n \"hostname of your SMTP email server.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"host\", $$v)\n },\n expression: \"notifiers.email.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n min: 1,\n step: 1,\n label: \"SMTP port\",\n id: \"email_port\",\n explanations: [\n \"port number used to connect to your SMTP host.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.port,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"port\", $$v)\n },\n expression: \"notifiers.email.port\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP from\",\n id: \"email_from\",\n explanations: [\n \"sender email address, some hosts require a real address.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.from,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"from\", $$v)\n },\n expression: \"notifiers.email.from\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Use TLS\",\n id: \"email_tls\",\n explanations: [\"check to use TLS encryption.\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.tls,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"tls\", $$v)\n },\n expression: \"notifiers.email.tls\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP username\",\n id: \"email_username\",\n explanations: [\n \"(optional) your SMTP server username.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.email.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"SMTP password\",\n id: \"email_password\",\n explanations: [\n \"(optional) your SMTP server password.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.email.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_list\",\n label: \"Global email list\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.notifiers.email.addressList\n },\n on: { change: _vm.emailUpdateAddressList }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Email Subject\",\n id: \"email_subject\",\n explanations: [\n \"Use a custom subject for some privacy protection?\",\n \"(Leave blank for the default Medusa subject)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.subject,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"subject\",\n $$v\n )\n },\n expression: \"notifiers.email.subject\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_show\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.emailUpdateShowEmail($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.emailSelectedShowAdresses\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"email\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEmail-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Email\",\n id: \"testEmail\"\n },\n on: { click: _vm.testEmail }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-slack\",\n attrs: { title: \"Slack\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://slack.com\" } },\n [_vm._v(\"Slack\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"Slack is a messaging app for teams.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_slack_client\",\n explanations: [\"Send Slack notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.slack, \"enabled\", $$v)\n },\n expression: \"notifiers.slack.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.slack.enabled,\n expression: \"notifiers.slack.enabled\"\n }\n ],\n attrs: { id: \"content-use-slack-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"slack_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"slack_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"slack_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.slack\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.slack.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Slack Incoming Webhook\",\n id: \"slack_webhook\",\n explanations: [\n \"Create an incoming webhook, to communicate with your slack channel.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.slack.webhook\"\n }\n },\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://my.slack.com/services/new/incoming-webhook\"\n }\n },\n [\n _vm._v(\n \"https://my.slack.com/services/new/incoming-webhook/\"\n )\n ]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testSlack-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Slack\",\n id: \"testSlack\"\n },\n on: { click: _vm.testSlack }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"br\"),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"br\")\n ])\n ]\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clearfix\" })\n ],\n 1\n )\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"label\",\n { staticClass: \"col-sm-2 control-label\", attrs: { for: \"kodi_host\" } },\n [_c(\"span\", [_vm._v(\"KODI IP:Port\")])]\n )\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"clear-left\" }, [\n _c(\"p\", [\n _c(\"b\", [_vm._v(\"Note:\")]),\n _vm._v(\" some Plex Home Theaters \"),\n _c(\"b\", { staticClass: \"boldest\" }, [_vm._v(\"do not\")]),\n _vm._v(\" support notifications e.g. Plexapp for Samsung TVs\")\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"render\": () => /* binding */ render,\n/* harmony export */ \"staticRenderFns\": () => /* binding */ staticRenderFns\n/* harmony export */ });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"config-notifications\" } },\n [\n _c(\"vue-snotify\"),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"config\" } }, [\n _c(\"div\", { attrs: { id: \"config-content\" } }, [\n _c(\n \"form\",\n {\n attrs: { id: \"configForm\", method: \"post\" },\n on: {\n submit: function($event) {\n $event.preventDefault()\n return _vm.save()\n }\n }\n },\n [\n _c(\"div\", { attrs: { id: \"config-components\" } }, [\n _c(\"ul\", [\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#home-theater-nas\" } }, [\n _vm._v(\"Home Theater / NAS\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#devices\" } }, [\n _vm._v(\"Devices\")\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"li\",\n [\n _c(\"app-link\", { attrs: { href: \"#social\" } }, [\n _vm._v(\"Social\")\n ])\n ],\n 1\n )\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"home-theater-nas\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-kodi\",\n attrs: { title: \"KODI\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://kodi.tv\" } },\n [_vm._v(\"KODI\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A free and open source cross-platform media center and home entertainment system software with a 10-foot user interface designed for the living-room TV.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_kodi\",\n explanations: [\"Send KODI commands?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.kodi, \"enabled\", $$v)\n },\n expression: \"notifiers.kodi.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.kodi.enabled,\n expression: \"notifiers.kodi.enabled\"\n }\n ],\n attrs: { id: \"content-use-kodi\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Always on\",\n id: \"kodi_always_on\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.alwaysOn,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"alwaysOn\",\n $$v\n )\n },\n expression: \"notifiers.kodi.alwaysOn\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"kodi_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"kodi_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.kodi.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"kodi_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.kodi.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.kodi.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update library\",\n id: \"kodi_update_library\",\n explanations: [\n \"update KODI library when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.library,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"library\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.library\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Full library update\",\n id: \"kodi_update_full\",\n explanations: [\n \"perform a full library update if update per-show fails?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.full,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"full\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.full\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Clean library\",\n id: \"kodi_clean_library\",\n explanations: [\n \"clean KODI library when replaces a already downloaded episode?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.cleanLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"cleanLibrary\",\n $$v\n )\n },\n expression: \"notifiers.kodi.cleanLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Only update first host\",\n id: \"kodi_update_onlyfirst\",\n explanations: [\n \"only send library updates/clean to the first active host?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.update.onlyFirst,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi.update,\n \"onlyFirst\",\n $$v\n )\n },\n expression: \"notifiers.kodi.update.onlyFirst\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _vm._m(0),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"col-sm-10 content\" },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"kodi_host\",\n id: \"kodi_host\",\n \"list-items\": _vm.notifiers.kodi.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.kodi.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"host running KODI (eg. 192.168.1.100:8080)\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"kodi_username\",\n explanations: [\n \"username for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.kodi.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"kodi_password\",\n explanations: [\n \"password for your KODI server (blank for none)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.kodi.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.kodi,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.kodi.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testKODI-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test KODI\",\n id: \"testKODI\"\n },\n on: { click: _vm.testKODI }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plex\",\n attrs: { title: \"Plex Media Server\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Media Server\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Experience your media on a visually stunning, easy to use interface on your Mac connected to your TV. Your media library has never looked this good!\"\n )\n ]),\n _vm._v(\" \"),\n _vm.notifiers.plex.server.enabled\n ? _c(\"p\", { staticClass: \"plexinfo\" }, [\n _vm._v(\n \"For sending notifications to Plex Home Theater (PHT) clients, use the KODI notifier with port \"\n ),\n _c(\"b\", [_vm._v(\"3005\")]),\n _vm._v(\".\")\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_server\",\n explanations: [\"Send Plex server notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.server.enabled,\n expression: \"notifiers.plex.server.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-server\" }\n },\n [\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Plex Media Server Auth Token\",\n id: \"plex_server_token\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.token,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"token\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.token\"\n }\n },\n [\n _c(\"p\", [_vm._v(\"Auth Token used by plex\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\n \"span\",\n [\n _vm._v(\"See: \"),\n _c(\n \"app-link\",\n {\n staticClass: \"wiki\",\n attrs: {\n href:\n \"https://support.plex.tv/hc/en-us/articles/204059436-Finding-your-account-token-X-Plex-Token\"\n }\n },\n [\n _c(\"strong\", [\n _vm._v(\n \"Finding your account token\"\n )\n ])\n ]\n )\n ],\n 1\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_server_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_server_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Update Library\",\n id: \"plex_update_library\",\n explanations: [\"log errors when unreachable?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.server.updateLibrary,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"updateLibrary\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.server.updateLibrary\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_server_host\",\n label: \"Plex Media Server IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_server_host\",\n id: \"plex_server_host\",\n \"list-items\":\n _vm.notifiers.plex.server.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.server.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Media Server\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.1:32400, 192.168.1.2:32400)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"plex_server_https\",\n explanations: [\n \"use https for plex media server requests?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.server.https,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.server,\n \"https\",\n $$v\n )\n },\n expression: \"notifiers.plex.server.https\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPMS-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Media Server(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Media Server\",\n id: \"testPMS\"\n },\n on: { click: _vm.testPMS }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clear-left\" }, [\n _vm._v(\" \")\n ])\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-plexth\",\n attrs: { title: \"Plex Media Client\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://plex.tv\" } },\n [_vm._v(\"Plex Home Theater\")]\n )\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_plex_client\",\n explanations: [\n \"Send Plex Home Theater notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.plex.client.enabled,\n expression: \"notifiers.plex.client.enabled\"\n }\n ],\n attrs: { id: \"content-use-plex-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"plex_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"plex_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"plex_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.plex.client\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.plex.client.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"plex_client_host\",\n label: \"Plex Home Theater IP:Port\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"plex_client_host\",\n id: \"plex_client_host\",\n \"list-items\":\n _vm.notifiers.plex.client.host\n },\n on: {\n change: function($event) {\n _vm.notifiers.plex.client.host = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"one or more hosts running Plex Home Theater\"\n ),\n _c(\"br\"),\n _vm._v(\n \"(eg. 192.168.1.100:3000, 192.168.1.101:3000)\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Username\",\n id: \"plex_client_username\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"plex_client_password\",\n explanations: [\"blank = no authentication\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.plex.client.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.plex.client,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.plex.client.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"field-pair\" }, [\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPHT-result\" }\n },\n [\n _vm._v(\n \"Click below to test Plex Home Theater(s)\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Plex Home Theater\",\n id: \"testPHT\"\n },\n on: { click: _vm.testPHT }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _vm._m(1)\n ])\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-emby\",\n attrs: { title: \"Emby\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://emby.media\" } },\n [_vm._v(\"Emby\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A home media server built using other popular open source technologies.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_emby\",\n explanations: [\"Send update commands to Emby?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"enabled\", $$v)\n },\n expression: \"notifiers.emby.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.emby.enabled,\n expression: \"notifiers.emby.enabled\"\n }\n ],\n attrs: { id: \"content_use_emby\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Emby IP:Port\",\n id: \"emby_host\",\n explanations: [\n \"host running Emby (eg. 192.168.1.100:8096)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"host\", $$v)\n },\n expression: \"notifiers.emby.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: { label: \"Api Key\", id: \"emby_apikey\" },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.emby.apiKey,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.emby, \"apiKey\", $$v)\n },\n expression: \"notifiers.emby.apiKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEMBY-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Emby\",\n id: \"testEMBY\"\n },\n on: { click: _vm.testEMBY }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJ\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJ, is the official media jukebox interface made available for the Popcorn Hour 200-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmj\",\n explanations: [\"Send update commands to NMJ?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"enabled\", $$v)\n },\n expression: \"notifiers.nmj.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmj.enabled,\n expression: \"notifiers.nmj.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmj\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmj_host\",\n explanations: [\n \"IP address of Popcorn 200-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"host\", $$v)\n },\n expression: \"notifiers.nmj.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"settingsNMJ\",\n label: \"Get settings\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Get Settings\",\n id: \"settingsNMJ\"\n },\n on: { click: _vm.settingsNMJ }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on and NMJ running.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ database\",\n id: \"nmj_database\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.database,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"database\", $$v)\n },\n expression: \"notifiers.nmj.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJ mount\",\n id: \"nmj_mount\",\n explanations: [\n \"automatically filled via the 'Get Settings' button.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmj.mount,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmj, \"mount\", $$v)\n },\n expression: \"notifiers.nmj.mount\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJ-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJ\",\n id: \"testNMJ\"\n },\n on: { click: _vm.testNMJ }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-nmj\",\n attrs: { title: \"Networked Media Jukebox v2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: { href: \"http://www.popcornhour.com/\" }\n },\n [_vm._v(\"NMJv2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"The Networked Media Jukebox, or NMJv2, is the official media jukebox interface made available for the Popcorn Hour 300 & 400-series.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_nmjv2\",\n explanations: [\n \"Send popcorn hour (nmjv2) notifications?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"enabled\", $$v)\n },\n expression: \"notifiers.nmjv2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.nmjv2.enabled,\n expression: \"notifiers.nmjv2.enabled\"\n }\n ],\n attrs: { id: \"content-use-nmjv2\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"Popcorn IP address\",\n id: \"nmjv2_host\",\n explanations: [\n \"IP address of Popcorn 300/400-series (eg. 192.168.1.100)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.nmjv2, \"host\", $$v)\n },\n expression: \"notifiers.nmjv2.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_location\",\n label: \"Database location\"\n }\n },\n [\n _c(\n \"label\",\n {\n staticClass: \"space-right\",\n attrs: { for: \"NMJV2_DBLOC_A\" }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"local\",\n id: \"NMJV2_DBLOC_A\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Local Media\\n \"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"label\",\n { attrs: { for: \"NMJV2_DBLOC_B\" } },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.nmjv2.dbloc,\n expression: \"notifiers.nmjv2.dbloc\"\n }\n ],\n attrs: {\n type: \"radio\",\n name: \"nmjv2_dbloc\",\n VALUE: \"network\",\n id: \"NMJV2_DBLOC_B\"\n },\n domProps: {\n checked: _vm._q(\n _vm.notifiers.nmjv2.dbloc,\n null\n )\n },\n on: {\n change: function($event) {\n return _vm.$set(\n _vm.notifiers.nmjv2,\n \"dbloc\",\n null\n )\n }\n }\n }),\n _vm._v(\n \"\\n PCH Network Media\\n \"\n )\n ]\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"nmjv2_database_instance\",\n label: \"Database instance\"\n }\n },\n [\n _c(\n \"select\",\n {\n staticClass: \"form-control input-sm\",\n attrs: { id: \"NMJv2db_instance\" }\n },\n [\n _c(\"option\", { attrs: { value: \"0\" } }, [\n _vm._v(\"#1 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"1\" } }, [\n _vm._v(\"#2 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"2\" } }, [\n _vm._v(\"#3 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"3\" } }, [\n _vm._v(\"#4 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"4\" } }, [\n _vm._v(\"#5 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"5\" } }, [\n _vm._v(\"#6 \")\n ]),\n _vm._v(\" \"),\n _c(\"option\", { attrs: { value: \"6\" } }, [\n _vm._v(\"#7 \")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"adjust this value if the wrong database is selected.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"get_nmjv2_find_database\",\n label: \"Find database\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Find Database\",\n id: \"settingsNMJv2\"\n },\n on: { click: _vm.settingsNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"the Popcorn Hour device must be powered on.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"NMJv2 database\",\n id: \"nmjv2_database\",\n explanations: [\n \"automatically filled via the 'Find Database' buttons.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.nmjv2.database,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.nmjv2,\n \"database\",\n $$v\n )\n },\n expression: \"notifiers.nmjv2.database\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testNMJv2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test NMJv2\",\n id: \"testNMJv2\"\n },\n on: { click: _vm.testNMJv2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno1\",\n attrs: { title: \"Synology\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"The Synology DiskStation NAS.\")]),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Indexer is the daemon running on the Synology NAS to build its media database.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"HTTPS\",\n id: \"use_synoindex\",\n explanations: [\n \"Note: requires Medusa to be running on your Synology NAS.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synologyIndex.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synologyIndex,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.synologyIndex.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synologyIndex.enabled,\n expression: \"notifiers.synologyIndex.enabled\"\n }\n ],\n attrs: { id: \"content_use_synoindex\" }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ]\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-syno2\",\n attrs: { title: \"Synology Indexer\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://synology.com/\" } },\n [_vm._v(\"Synology Notifier\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Synology Notifier is the notification system of Synology DSM\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_synologynotifier\",\n explanations: [\n \"Send notifications to the Synology Notifier?\",\n \"Note: requires Medusa to be running on your Synology DSM.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.synology, \"enabled\", $$v)\n },\n expression: \"notifiers.synology.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.synology.enabled,\n expression: \"notifiers.synology.enabled\"\n }\n ],\n attrs: { id: \"content-use-synology-notifier\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.synology.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"synology_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"synology_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.synology\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.synology,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.synology.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pytivo\",\n attrs: { title: \"pyTivo\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://pytivo.sourceforge.net/wiki/index.php/PyTivo\"\n }\n },\n [_vm._v(\"pyTivo\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pytivo\",\n explanations: [\"Send notifications to pyTivo?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"enabled\", $$v)\n },\n expression: \"notifiers.pyTivo.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pyTivo.enabled,\n expression: \"notifiers.pyTivo.enabled\"\n }\n ],\n attrs: { id: \"content-use-pytivo\" }\n },\n [\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo IP:Port\",\n id: \"pytivo_host\",\n explanations: [\n \"host running pyTivo (eg. 192.168.1.1:9032)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"host\", $$v)\n },\n expression: \"notifiers.pyTivo.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"pyTivo share name\",\n id: \"pytivo_name\",\n explanations: [\n \"(Messages & Settings > Account & System Information > System Information > DVR name)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.shareName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pyTivo,\n \"shareName\",\n $$v\n )\n },\n expression: \"notifiers.pyTivo.shareName\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Tivo name\",\n id: \"pytivo_tivo_name\",\n explanations: [\n \"value used in pyTivo Web Configuration to name the share.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pyTivo.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pyTivo, \"name\", $$v)\n },\n expression: \"notifiers.pyTivo.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"devices\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-growl\",\n attrs: { title: \"Growl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://growl.info/\" } },\n [_vm._v(\"Growl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A cross-platform unobtrusive global notification system.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_growl_client\",\n explanations: [\"Send Growl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"enabled\", $$v)\n },\n expression: \"notifiers.growl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.growl.enabled,\n expression: \"notifiers.growl.enabled\"\n }\n ],\n attrs: { id: \"content-use-growl-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"growl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"growl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.growl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"growl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.growl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.growl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Growl IP:Port\",\n id: \"growl_host\",\n explanations: [\n \"host running Growl (eg. 192.168.1.100:23053)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.growl, \"host\", $$v)\n },\n expression: \"notifiers.growl.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"Password\",\n id: \"growl_password\",\n explanations: [\n \"may leave blank if Medusa is on the same host.\",\n \"otherwise Growl requires a password to be used.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.growl.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.growl,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.growl.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testGrowl-result\" }\n },\n [\n _vm._v(\n \"Click below to register and test Growl, this is required for Growl notifications to work.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Register Growl\",\n id: \"testGrowl\"\n },\n on: { click: _vm.testGrowl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-prowl\",\n attrs: { title: \"Prowl\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://www.prowlapp.com/\" } },\n [_vm._v(\"Prowl\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"A Growl client for iOS.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_prowl\",\n explanations: [\"Send Prowl notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.prowl, \"enabled\", $$v)\n },\n expression: \"notifiers.prowl.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.prowl.enabled,\n expression: \"notifiers.prowl.enabled\"\n }\n ],\n attrs: { id: \"content-use-prowl\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"prowl_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"prowl_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.prowl.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"prowl_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.prowl\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.prowl.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Prowl Message Title\",\n id: \"prowl_message_title\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.prowl.messageTitle,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.prowl,\n \"messageTitle\",\n $$v\n )\n },\n expression: \"notifiers.prowl.messageTitle\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_api\",\n label: \"Api\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl_api\",\n id: \"prowl_api\",\n \"csv-enabled\": \"\",\n \"list-items\": _vm.notifiers.prowl.api\n },\n on: { change: _vm.onChangeProwlApi }\n }),\n _vm._v(\" \"),\n _c(\n \"span\",\n [\n _vm._v(\n \"Prowl API(s) listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\n \" shows.\\n Your Prowl API key is available at:\\n \"\n ),\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://www.prowlapp.com/api_settings.php\"\n }\n },\n [\n _vm._v(\n \"\\n https://www.prowlapp.com/api_settings.php\"\n )\n ]\n ),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_show_notification_list\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.prowlUpdateApiKeys($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"prowl-show-list\",\n id: \"prowl-show-list\",\n \"list-items\":\n _vm.prowlSelectedShowApiKeys\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"prowl\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Configure per-show notifications here by entering Prowl API key(s), after selecting a show in the drop-down box.\\n Be sure to activate the 'Save for this show' button below after each entry.\\n \"\n ),\n _c(\"span\", [\n _vm._v(\n \"The values are automatically saved when adding the api key.\"\n )\n ])\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"prowl_priority\",\n label: \"Prowl priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.prowl.priority,\n expression: \"notifiers.prowl.priority\"\n }\n ],\n staticClass: \"form-control input-sm\",\n attrs: {\n id: \"prowl_priority\",\n name: \"prowl_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.prowl,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.prowlPriorityOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Prowl messages from Medusa.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testProwl-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Prowl\",\n id: \"testProwl\"\n },\n on: { click: _vm.testProwl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-libnotify\",\n attrs: { title: \"Libnotify\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"http://library.gnome.org/devel/libnotify/\"\n }\n },\n [_vm._v(\"Libnotify\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"p\",\n [\n _vm._v(\n \"The standard desktop notification API for Linux/*nix systems. This notifier will only function if the pynotify module is installed (Ubuntu/Debian package \"\n ),\n _c(\n \"app-link\",\n { attrs: { href: \"apt:python-notify\" } },\n [_vm._v(\"python-notify\")]\n ),\n _vm._v(\").\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_libnotify_client\",\n explanations: [\"Send Libnotify notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.libnotify.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.libnotify.enabled,\n expression: \"notifiers.libnotify.enabled\"\n }\n ],\n attrs: { id: \"content-use-libnotify\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"libnotify_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.libnotify.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"libnotify_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"libnotify_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.libnotify\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.libnotify,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.libnotify.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testLibnotify-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Libnotify\",\n id: \"testLibnotify\"\n },\n on: { click: _vm.testLibnotify }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushover\",\n attrs: { title: \"Pushover\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushover.net/\" } },\n [_vm._v(\"Pushover\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushover makes it easy to send real-time notifications to your Android and iOS devices.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushover_client\",\n explanations: [\"Send Pushover notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushover, \"enabled\", $$v)\n },\n expression: \"notifiers.pushover.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushover.enabled,\n expression: \"notifiers.pushover.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushover\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushover_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushover_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushover_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushover\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushover.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushover User Key\",\n id: \"pushover_userkey\",\n explanations: [\n \"User Key of your Pushover account\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.userKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"userKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.userKey\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Pushover API Key\",\n id: \"pushover_apikey\"\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushover.apiKey,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushover,\n \"apiKey\",\n $$v\n )\n },\n expression: \"notifiers.pushover.apiKey\"\n }\n },\n [\n _c(\n \"span\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://pushover.net/apps/build/\"\n }\n },\n [_c(\"b\", [_vm._v(\"Click here\")])]\n ),\n _vm._v(\" to create a Pushover API key\")\n ],\n 1\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_device\",\n label: \"Pushover Devices\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"pushover_device\",\n id: \"pushover_device\",\n \"list-items\":\n _vm.notifiers.pushover.device\n },\n on: {\n change: function($event) {\n _vm.notifiers.pushover.device = $event.map(\n function(x) {\n return x.value\n }\n )\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"List of pushover devices you want to send notifications to\"\n )\n ])\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_sound\",\n label: \"Pushover notification sound\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.notifiers.pushover.sound,\n expression: \"notifiers.pushover.sound\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_sound\",\n name: \"pushover_sound\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"sound\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.pushoverSoundOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"Choose notification sound to use\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushover_priority\",\n label: \"Pushover notification priority\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushover.priority,\n expression:\n \"notifiers.pushover.priority\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushover_priority\",\n name: \"pushover_priority\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushover,\n \"priority\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushoverPriorityOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\n \"priority of Pushover messages from Medusa\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushover-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushover\",\n id: \"testPushover\"\n },\n on: { click: _vm.testPushover }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-boxcar2\",\n attrs: { title: \"Boxcar 2\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://new.boxcar.io/\" } },\n [_vm._v(\"Boxcar 2\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Read your messages where and when you want them!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_boxcar2\",\n explanations: [\"Send boxcar2 notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.boxcar2, \"enabled\", $$v)\n },\n expression: \"notifiers.boxcar2.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.boxcar2.enabled,\n expression: \"notifiers.boxcar2.enabled\"\n }\n ],\n attrs: { id: \"content-use-boxcar2-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"boxcar2_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"boxcar2_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"boxcar2_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.boxcar2\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.boxcar2.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Boxcar2 Access token\",\n id: \"boxcar2_accesstoken\",\n explanations: [\n \"access token for your Boxcar account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.boxcar2.accessToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.boxcar2,\n \"accessToken\",\n $$v\n )\n },\n expression: \"notifiers.boxcar2.accessToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testBoxcar2-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Boxcar\",\n id: \"testBoxcar2\"\n },\n on: { click: _vm.testBoxcar2 }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushalot\",\n attrs: { title: \"Pushalot\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://pushalot.com\" } },\n [_vm._v(\"Pushalot\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushalot is a platform for receiving custom push notifications to connected devices running Windows Phone or Windows 8.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushalot\",\n explanations: [\"Send Pushalot notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.pushalot, \"enabled\", $$v)\n },\n expression: \"notifiers.pushalot.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushalot.enabled,\n expression: \"notifiers.pushalot.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushalot-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushalot_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushalot_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushalot_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushalot\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushalot.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushalot authorization token\",\n id: \"pushalot_authorizationtoken\",\n explanations: [\n \"authorization token of your Pushalot account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushalot.authToken,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushalot,\n \"authToken\",\n $$v\n )\n },\n expression: \"notifiers.pushalot.authToken\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushalot-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushalot\",\n id: \"testPushalot\"\n },\n on: { click: _vm.testPushalot }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-pushbullet\",\n attrs: { title: \"Pushbullet\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.pushbullet.com\" } },\n [_vm._v(\"Pushbullet\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Pushbullet is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_pushbullet\",\n explanations: [\"Send pushbullet notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.pushbullet.enabled,\n expression: \"notifiers.pushbullet.enabled\"\n }\n ],\n attrs: { id: \"content-use-pushbullet-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"pushbullet_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"pushbullet_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"pushbullet_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.pushbullet\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.pushbullet.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Pushbullet API key\",\n id: \"pushbullet_api\",\n explanations: [\n \"API key of your Pushbullet account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.pushbullet.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.pushbullet.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"pushbullet_device_list\",\n label: \"Pushbullet devices\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Update device list\",\n id: \"get-pushbullet-devices\"\n },\n on: {\n click: _vm.getPushbulletDeviceOptions\n }\n }),\n _vm._v(\" \"),\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.pushbullet.device,\n expression:\n \"notifiers.pushbullet.device\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"pushbullet_device_list\",\n name: \"pushbullet_device_list\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.pushbullet,\n \"device\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(\n _vm.pushbulletDeviceOptions,\n function(option) {\n return _c(\n \"option\",\n {\n key: option.value,\n domProps: { value: option.value },\n on: {\n change: function($event) {\n _vm.pushbulletTestInfo =\n \"Don't forget to save your new pushbullet settings.\"\n }\n }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }\n ),\n 0\n ),\n _vm._v(\" \"),\n _c(\"span\", [\n _vm._v(\"select device you wish to push to.\")\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testPushbullet-resultsfsf\" }\n },\n [_vm._v(_vm._s(_vm.pushbulletTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Pushbullet\",\n id: \"testPushbullet\"\n },\n on: { click: _vm.testPushbulletApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-join\",\n attrs: { title: \"Join\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://joaoapps.com/join/\" } },\n [_vm._v(\"Join\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Join is a platform for receiving custom push notifications to connected devices running Android and desktop Chrome browsers.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_join\",\n explanations: [\"Send join notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"enabled\", $$v)\n },\n expression: \"notifiers.join.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.join.enabled,\n expression: \"notifiers.join.enabled\"\n }\n ],\n attrs: { id: \"content-use-join-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"join_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"join_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.join.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"join_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.join.notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.join,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.join.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join API key\",\n id: \"join_api\",\n explanations: [\n \"API key of your Join account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"api\", $$v)\n },\n expression: \"notifiers.join.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Join Device ID(s) key\",\n id: \"join_device\",\n explanations: [\n \"Enter DeviceID of the device(s) you wish to send notifications to, comma separated if using multiple.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.join.device,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.join, \"device\", $$v)\n },\n expression: \"notifiers.join.device\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testJoin-result\" }\n },\n [_vm._v(_vm._s(_vm.joinTestInfo))]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Join\",\n id: \"testJoin\"\n },\n on: { click: _vm.testJoinApi }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-freemobile\",\n attrs: { title: \"Free Mobile\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"http://mobile.free.fr/\" } },\n [_vm._v(\"Free Mobile\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Free Mobile is a famous French cellular network provider. It provides to their customer a free SMS API.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_freemobile\",\n explanations: [\"Send SMS notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.enabled,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"enabled\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.freemobile.enabled,\n expression: \"notifiers.freemobile.enabled\"\n }\n ],\n attrs: { id: \"content-use-freemobile-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"freemobile_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"freemobile_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"freemobile_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.freemobile\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.freemobile.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile customer ID\",\n id: \"freemobile_id\",\n explanations: [\n \"It's your Free Mobile customer ID (8 digits)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.id,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"id\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Free Mobile API Key\",\n id: \"freemobile_apikey\",\n explanations: [\n \"Find your API Key in your customer portal.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.freemobile.api,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.freemobile,\n \"api\",\n $$v\n )\n },\n expression: \"notifiers.freemobile.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testFreeMobile-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test SMS\",\n id: \"testFreeMobile\"\n },\n on: { click: _vm.testFreeMobile }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-telegram\",\n attrs: { title: \"Telegram\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://telegram.org/\" } },\n [_vm._v(\"Telegram\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Telegram is a cloud-based instant messaging service.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_telegram\",\n explanations: [\"Send Telegram notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"enabled\", $$v)\n },\n expression: \"notifiers.telegram.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.telegram.enabled,\n expression: \"notifiers.telegram.enabled\"\n }\n ],\n attrs: { id: \"content-use-telegram-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"telegram_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"telegram_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"telegram_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.telegram\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.telegram,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.telegram.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"User/group ID\",\n id: \"telegram_id\",\n explanations: [\n \"Contact @myidbot on Telegram to get an ID\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.id,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"id\", $$v)\n },\n expression: \"notifiers.telegram.id\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot API token\",\n id: \"telegram_apikey\",\n explanations: [\n \"Contact @BotFather on Telegram to set up one\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.telegram.api,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.telegram, \"api\", $$v)\n },\n expression: \"notifiers.telegram.api\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTelegram-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Telegram\",\n id: \"testTelegram\"\n },\n on: { click: _vm.testTelegram }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-discord\",\n attrs: { title: \"Discord\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://discordapp.com/\" } },\n [_vm._v(\"Discord\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Discord is a cloud-based All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone..\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_discord\",\n explanations: [\"Send Discord notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"enabled\", $$v)\n },\n expression: \"notifiers.discord.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.discord.enabled,\n expression: \"notifiers.discord.enabled\"\n }\n ],\n attrs: { id: \"content-use-discord-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"discord_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.discord.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"discord_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"discord_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.discord\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.discord.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Channel webhook\",\n id: \"discord_webhook\",\n explanations: [\n \"Add a webhook to a channel, use the returned url here\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.discord,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.discord.webhook\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Text to speech\",\n id: \"discord_tts\",\n explanations: [\n \"Use discord text to speech feature\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.tts,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"tts\", $$v)\n },\n expression: \"notifiers.discord.tts\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Bot username\",\n id: \"discord_name\",\n explanations: [\n \"Create a username for the Discord Bot to use\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.discord.name,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.discord, \"name\", $$v)\n },\n expression: \"notifiers.discord.name\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testDiscord-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Discord\",\n id: \"testDiscord\"\n },\n on: { click: _vm.testDiscord }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { attrs: { id: \"social\" } }, [\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-twitter\",\n attrs: { title: \"Twitter\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://www.twitter.com\" } },\n [_vm._v(\"Twitter\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"A social networking and microblogging service, enabling its users to send and read other users' messages called tweets.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_twitter\",\n explanations: [\n \"Should Medusa post tweets on Twitter?\",\n \"Note: you may want to use a secondary account.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"enabled\", $$v)\n },\n expression: \"notifiers.twitter.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.twitter.enabled,\n expression: \"notifiers.twitter.enabled\"\n }\n ],\n attrs: { id: \"content-use-twitter\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"twitter_notify_onsnatch\",\n explanations: [\n \"send an SMS when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.twitter.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"twitter_notify_ondownload\",\n explanations: [\n \"send an SMS when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"twitter_notify_onsubtitledownload\",\n explanations: [\n \"send an SMS when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.twitter\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.twitter.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Send direct message\",\n id: \"twitter_usedm\",\n explanations: [\n \"send a notification via Direct Message, not via status update\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.directMessage,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.twitter,\n \"directMessage\",\n $$v\n )\n },\n expression: \"notifiers.twitter.directMessage\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Send DM to\",\n id: \"twitter_dmto\",\n explanations: [\n \"Twitter account to send Direct Messages to (must follow you)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.twitter.dmto,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.twitter, \"dmto\", $$v)\n },\n expression: \"notifiers.twitter.dmto\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep1\",\n label: \"Step 1\"\n }\n },\n [\n _c(\n \"span\",\n { staticStyle: { \"font-size\": \"11px\" } },\n [\n _vm._v(\n 'Click the \"Request Authorization\" button. '\n ),\n _c(\"br\"),\n _vm._v(\n \"This will open a new page containing an auth key. \"\n ),\n _c(\"br\"),\n _vm._v(\n \"Note: if nothing happens check your popup blocker.\"\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Request Authorization\",\n id: \"twitter-step-1\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep1($event)\n }\n }\n })\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"twitterStep2\",\n label: \"Step 2\"\n }\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.twitterKey,\n expression: \"twitterKey\"\n }\n ],\n staticClass:\n \"form-control input-sm max-input350\",\n staticStyle: { display: \"inline\" },\n attrs: {\n type: \"text\",\n id: \"twitter_key\",\n placeholder:\n \"Enter the key Twitter gave you, and click 'Verify Key'\"\n },\n domProps: { value: _vm.twitterKey },\n on: {\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.twitterKey = $event.target.value\n }\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa btn-inline\",\n attrs: {\n type: \"button\",\n value: \"Verify Key\",\n id: \"twitter-step-2\"\n },\n on: {\n click: function($event) {\n return _vm.twitterStep2($event)\n }\n }\n })\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", {\n staticClass: \"testNotification\",\n attrs: { id: \"testTwitter-result\" },\n domProps: {\n innerHTML: _vm._s(_vm.twitterTestInfo)\n }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Twitter\",\n id: \"testTwitter\"\n },\n on: { click: _vm.twitterTest }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\"a\", { attrs: { href: \"#trakt\" } }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-trakt\",\n attrs: { title: \"Trakt\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://trakt.tv/\" } },\n [_vm._v(\"Trakt\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_trakt\",\n explanations: [\"Send Trakt.tv notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"enabled\", $$v)\n },\n expression: \"notifiers.trakt.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.enabled,\n expression: \"notifiers.trakt.enabled\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_request_auth\",\n label: \"\"\n }\n },\n [\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Connect to your trakt account\",\n id: \"Trakt\"\n },\n on: { click: _vm.TraktRequestDeviceCode }\n }),\n _vm._v(\" \"),\n _vm.traktRequestSend && _vm.traktUserCode\n ? _c(\n \"span\",\n { staticStyle: { display: \"inline\" } },\n [\n _vm._v(\n \"Use this code in the popup: \" +\n _vm._s(_vm.traktUserCode)\n )\n ]\n )\n : _vm._e(),\n _vm._v(\" \"),\n _vm.traktRequestSend &&\n _vm.traktUserCode &&\n _vm.traktRequestMessage\n ? _c(\"p\", [\n _vm._v(\n \"Trakt request status: \" +\n _vm._s(_vm.traktRequestMessage)\n )\n ])\n : _vm._e(),\n _vm._v(\" \"),\n _vm.traktRequestAuthenticated &&\n _vm.traktRequestMessage\n ? _c(\"p\", [\n _vm._v(_vm._s(_vm.traktRequestMessage))\n ])\n : _vm._e()\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n label: \"API Timeout\",\n id: \"trakt_timeout\",\n explanations: [\n \"Seconds to wait for Trakt API to respond. (Use 0 to wait forever)\"\n ]\n },\n model: {\n value: _vm.notifiers.trakt.timeout,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"timeout\",\n $$v\n )\n },\n expression: \"notifiers.trakt.timeout\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Default indexer\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.defaultIndexer,\n expression:\n \"notifiers.trakt.defaultIndexer\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_default_indexer\",\n name: \"trakt_default_indexer\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"defaultIndexer\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktIndexersOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n )\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync libraries\",\n id: \"trakt_sync\",\n explanations: [\n \"Sync your Medusa show library with your Trakt collection.\",\n \"Note: Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\",\n \"Kodi detects that the episode was deleted and removes from collection which causes Medusa to re-add it. This causes a loop between Medusa and Kodi adding and deleting the episode.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.sync,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.trakt, \"sync\", $$v)\n },\n expression: \"notifiers.trakt.sync\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.sync,\n expression: \"notifiers.trakt.sync\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove Episodes From Collection\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"Remove an Episode from your Trakt Collection if it is not in your Medusa Library.\",\n \"Note:Don't enable this setting if you use the Trakt addon for Kodi or any other script that syncs your library.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Sync watchlist\",\n id: \"trakt_sync_watchlist\",\n explanations: [\n \"Sync your Medusa library with your Trakt Watchlist (either Show and Episode).\",\n \"Episode will be added on watch list when wanted or snatched and will be removed when downloaded\",\n \"Note: By design, Trakt automatically removes episodes and/or shows from watchlist as soon you have watched them.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.syncWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"syncWatchlist\",\n $$v\n )\n },\n expression: \"notifiers.trakt.syncWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.trakt.syncWatchlist,\n expression:\n \"notifiers.trakt.syncWatchlist\"\n }\n ],\n attrs: { id: \"content-use-trakt-client\" }\n },\n [\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"trakt_default_indexer\",\n label: \"Watchlist add method\"\n }\n },\n [\n _c(\n \"select\",\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value:\n _vm.notifiers.trakt.methodAdd,\n expression:\n \"notifiers.trakt.methodAdd\"\n }\n ],\n staticClass: \"form-control\",\n attrs: {\n id: \"trakt_method_add\",\n name: \"trakt_method_add\"\n },\n on: {\n change: function($event) {\n var $$selectedVal = Array.prototype.filter\n .call(\n $event.target.options,\n function(o) {\n return o.selected\n }\n )\n .map(function(o) {\n var val =\n \"_value\" in o\n ? o._value\n : o.value\n return val\n })\n _vm.$set(\n _vm.notifiers.trakt,\n \"methodAdd\",\n $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n )\n }\n }\n },\n _vm._l(_vm.traktMethodOptions, function(\n option\n ) {\n return _c(\n \"option\",\n {\n key: option.key,\n domProps: { value: option.value }\n },\n [\n _vm._v(\n \"\\n \" +\n _vm._s(option.text) +\n \"\\n \"\n )\n ]\n )\n }),\n 0\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"method in which to download episodes for new shows.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove episode\",\n id: \"trakt_remove_watchlist\",\n explanations: [\n \"remove an episode from your watchlist after it's downloaded.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeWatchlist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeWatchlist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeWatchlist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove series\",\n id: \"trakt_remove_serieslist\",\n explanations: [\n \"remove the whole series from your watchlist after any download.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt.removeSerieslist,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeSerieslist\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeSerieslist\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Remove watched show\",\n id: \"trakt_remove_show_from_application\",\n explanations: [\n \"remove the show from Medusa if it's ended and completely watched\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.trakt\n .removeShowFromApplication,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"removeShowFromApplication\",\n $$v\n )\n },\n expression:\n \"notifiers.trakt.removeShowFromApplication\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Start paused\",\n id: \"trakt_start_paused\",\n explanations: [\n \"shows grabbed from your trakt watchlist start paused.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.startPaused,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"startPaused\",\n $$v\n )\n },\n expression: \"notifiers.trakt.startPaused\"\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Trakt blackList name\",\n id: \"trakt_blacklist_name\",\n explanations: [\n \"Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' & 'Add Recommended Shows' pages\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.trakt.blacklistName,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.trakt,\n \"blacklistName\",\n $$v\n )\n },\n expression: \"notifiers.trakt.blacklistName\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testTrakt-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Trakt\",\n id: \"testTrakt\"\n },\n on: { click: _vm.testTrakt }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Force Sync\",\n id: \"forceSync\"\n },\n on: { click: _vm.traktForceSync }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n attrs: { type: \"hidden\", id: \"trakt_pin_url\" },\n domProps: { value: _vm.notifiers.trakt.pinUrl }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-email\",\n attrs: { title: \"Email\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://en.wikipedia.org/wiki/Comparison_of_webmail_providers\"\n }\n },\n [_vm._v(\"Email\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [\n _vm._v(\n \"Allows configuration of email notifications on a per show basis.\"\n )\n ])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_email\",\n explanations: [\"Send email notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"enabled\", $$v)\n },\n expression: \"notifiers.email.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.email.enabled,\n expression: \"notifiers.email.enabled\"\n }\n ],\n attrs: { id: \"content-use-email\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"email_notify_onsnatch\",\n explanations: [\n \"Send a message when a download starts??\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"email_notify_ondownload\",\n explanations: [\n \"send a message when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.email.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"email_notify_onsubtitledownload\",\n explanations: [\n \"send a message when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.email\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.email.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP host\",\n id: \"email_host\",\n explanations: [\n \"hostname of your SMTP email server.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.host,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"host\", $$v)\n },\n expression: \"notifiers.email.host\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox-number\", {\n attrs: {\n min: 1,\n step: 1,\n label: \"SMTP port\",\n id: \"email_port\",\n explanations: [\n \"port number used to connect to your SMTP host.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.port,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"port\", $$v)\n },\n expression: \"notifiers.email.port\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP from\",\n id: \"email_from\",\n explanations: [\n \"sender email address, some hosts require a real address.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.from,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"from\", $$v)\n },\n expression: \"notifiers.email.from\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Use TLS\",\n id: \"email_tls\",\n explanations: [\"check to use TLS encryption.\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.tls,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.email, \"tls\", $$v)\n },\n expression: \"notifiers.email.tls\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"SMTP username\",\n id: \"email_username\",\n explanations: [\n \"(optional) your SMTP server username.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.username,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"username\",\n $$v\n )\n },\n expression: \"notifiers.email.username\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n type: \"password\",\n label: \"SMTP password\",\n id: \"email_password\",\n explanations: [\n \"(optional) your SMTP server password.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.password,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"password\",\n $$v\n )\n },\n expression: \"notifiers.email.password\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_list\",\n label: \"Global email list\"\n }\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.notifiers.email.addressList\n },\n on: { change: _vm.emailUpdateAddressList }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"config-textbox\", {\n attrs: {\n label: \"Email Subject\",\n id: \"email_subject\",\n explanations: [\n \"Use a custom subject for some privacy protection?\",\n \"(Leave blank for the default Medusa subject)\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.email.subject,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.email,\n \"subject\",\n $$v\n )\n },\n expression: \"notifiers.email.subject\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-template\",\n {\n attrs: {\n \"label-for\": \"email_show\",\n label: \"Show notification list\"\n }\n },\n [\n _c(\"show-selector\", {\n attrs: {\n \"select-class\":\n \"form-control input-sm max-input350\",\n placeholder: \"-- Select a Show --\"\n },\n on: {\n change: function($event) {\n return _vm.emailUpdateShowEmail($event)\n }\n }\n })\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"form-group\" }, [\n _c(\"div\", { staticClass: \"row\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"offset-sm-2 col-sm-offset-2 col-sm-10 content\"\n },\n [\n _c(\"select-list\", {\n attrs: {\n name: \"email_list\",\n id: \"email_list\",\n \"list-items\":\n _vm.emailSelectedShowAdresses\n },\n on: {\n change: function($event) {\n return _vm.savePerShowNotifyList(\n \"email\",\n $event\n )\n }\n }\n }),\n _vm._v(\n \"\\n Email addresses listed here, will receive notifications for \"\n ),\n _c(\"b\", [_vm._v(\"all\")]),\n _vm._v(\" shows.\"),\n _c(\"br\"),\n _vm._v(\n \"\\n (This field may be blank except when testing.)\\n \"\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testEmail-result\" }\n },\n [_vm._v(\"Click below to test.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Email\",\n id: \"testEmail\"\n },\n on: { click: _vm.testEmail }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"row component-group\" }, [\n _c(\n \"div\",\n {\n staticClass: \"component-group-desc col-xs-12 col-md-2\"\n },\n [\n _c(\"span\", {\n staticClass: \"icon-notifiers-slack\",\n attrs: { title: \"Slack\" }\n }),\n _vm._v(\" \"),\n _c(\n \"h3\",\n [\n _c(\n \"app-link\",\n { attrs: { href: \"https://slack.com\" } },\n [_vm._v(\"Slack\")]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\"p\", [_vm._v(\"Slack is a messaging app for teams.\")])\n ]\n ),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"col-xs-12 col-md-10\" }, [\n _c(\n \"fieldset\",\n { staticClass: \"component-group-list\" },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Enable\",\n id: \"use_slack_client\",\n explanations: [\"Send Slack notifications?\"]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.enabled,\n callback: function($$v) {\n _vm.$set(_vm.notifiers.slack, \"enabled\", $$v)\n },\n expression: \"notifiers.slack.enabled\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.notifiers.slack.enabled,\n expression: \"notifiers.slack.enabled\"\n }\n ],\n attrs: { id: \"content-use-slack-client\" }\n },\n [\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on snatch\",\n id: \"slack_notify_onsnatch\",\n explanations: [\n \"send a notification when a download starts?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnSnatch,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSnatch\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnSnatch\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on download\",\n id: \"slack_notify_ondownload\",\n explanations: [\n \"send a notification when a download finishes?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.notifyOnDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnDownload\",\n $$v\n )\n },\n expression: \"notifiers.slack.notifyOnDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\"config-toggle-slider\", {\n attrs: {\n label: \"Notify on subtitle download\",\n id: \"slack_notify_onsubtitledownload\",\n explanations: [\n \"send a notification when subtitles are downloaded?\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value:\n _vm.notifiers.slack\n .notifyOnSubtitleDownload,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"notifyOnSubtitleDownload\",\n $$v\n )\n },\n expression:\n \"notifiers.slack.notifyOnSubtitleDownload\"\n }\n }),\n _vm._v(\" \"),\n _c(\n \"config-textbox\",\n {\n attrs: {\n label: \"Slack Incoming Webhook\",\n id: \"slack_webhook\",\n explanations: [\n \"Create an incoming webhook, to communicate with your slack channel.\"\n ]\n },\n on: {\n change: function($event) {\n return _vm.save()\n }\n },\n model: {\n value: _vm.notifiers.slack.webhook,\n callback: function($$v) {\n _vm.$set(\n _vm.notifiers.slack,\n \"webhook\",\n $$v\n )\n },\n expression: \"notifiers.slack.webhook\"\n }\n },\n [\n _c(\n \"app-link\",\n {\n attrs: {\n href:\n \"https://my.slack.com/services/new/incoming-webhook\"\n }\n },\n [\n _vm._v(\n \"https://my.slack.com/services/new/incoming-webhook/\"\n )\n ]\n )\n ],\n 1\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"testNotification\",\n attrs: { id: \"testSlack-result\" }\n },\n [_vm._v(\"Click below to test your settings.\")]\n ),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa\",\n attrs: {\n type: \"button\",\n value: \"Test Slack\",\n id: \"testSlack\"\n },\n on: { click: _vm.testSlack }\n }),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ])\n ])\n ]),\n _vm._v(\" \"),\n _c(\"br\"),\n _vm._v(\" \"),\n _c(\"input\", {\n staticClass: \"btn-medusa config_submitter\",\n attrs: {\n type: \"submit\",\n value: \"Save Changes\",\n disabled: _vm.saving\n }\n }),\n _vm._v(\" \"),\n _c(\"br\")\n ])\n ]\n )\n ])\n ]),\n _vm._v(\" \"),\n _c(\"div\", { staticClass: \"clearfix\" })\n ],\n 1\n )\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"label\",\n { staticClass: \"col-sm-2 control-label\", attrs: { for: \"kodi_host\" } },\n [_c(\"span\", [_vm._v(\"KODI IP:Port\")])]\n )\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"clear-left\" }, [\n _c(\"p\", [\n _c(\"b\", [_vm._v(\"Note:\")]),\n _vm._v(\" some Plex Home Theaters \"),\n _c(\"b\", { staticClass: \"boldest\" }, [_vm._v(\"do not\")]),\n _vm._v(\" support notifications e.g. Plexapp for Samsung TVs\")\n ])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://slim/./src/components/config-notifications.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }),