/// <summary>
        /// Called when a subtitle search is done.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void SingleSubtitleSearchDone(object sender, EventArgs e)
        {
            _done.Add((SubtitleSearchEngine)sender);

            (sender as SubtitleSearchEngine).SubtitleSearchNewLink += SingleSubtitleSearchNewLink;
            (sender as SubtitleSearchEngine).SubtitleSearchDone    += SingleSubtitleSearchDone;
            (sender as SubtitleSearchEngine).SubtitleSearchError   += SingleSubtitleSearchError;

            SubtitleSearchEngineDone.Fire(this, SearchEngines.Except(_done).ToList());

            if (_done.Count == SearchEngines.Count)
            {
                Log.Debug("Search finished in " + (DateTime.Now - _start).TotalSeconds + "s.");
                SubtitleSearchDone.Fire(this);
            }
        }
        /// <summary>
        /// Called when a subtitle search has encountered an error.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void SingleSubtitleSearchError(object sender, EventArgs <string, Exception> e)
        {
            _done.Add((SubtitleSearchEngine)sender);

            (sender as SubtitleSearchEngine).SubtitleSearchNewLink += SingleSubtitleSearchNewLink;
            (sender as SubtitleSearchEngine).SubtitleSearchDone    += SingleSubtitleSearchDone;
            (sender as SubtitleSearchEngine).SubtitleSearchError   += SingleSubtitleSearchError;

            Log.Warn("Error while searching on " + ((SubtitleSearchEngine)sender).Name + ".", e.Second);

            SubtitleSearchEngineError.Fire(this, e.First, e.Second);
            SubtitleSearchEngineDone.Fire(this, SearchEngines.Except(_done).ToList());

            if (_done.Count == SearchEngines.Count)
            {
                Log.Debug("Search finished in " + (DateTime.Now - _start).TotalSeconds + "s.");
                SubtitleSearchDone.Fire(this);
            }
        }
        /// <summary>
        /// Synchronous search helper.
        /// </summary>
        /// <param name="query">The name of the release to search for.</param>
        private void SearchInternal(object query)
        {
            try
            {
                _cts.Token.ThrowIfCancellationRequested();
                var list = Search((string)query);
                _cts.Token.ThrowIfCancellationRequested();

                foreach (var sub in list)
                {
                    _cts.Token.ThrowIfCancellationRequested();
                    SubtitleSearchNewLink.Fire(this, sub);
                    _cts.Token.ThrowIfCancellationRequested();
                }

                _cts.Token.ThrowIfCancellationRequested();
                SubtitleSearchDone.Fire(this);
            }
            catch (InvalidCredentialException)
            {
                Log.Warn(Name + " requires authentication.");

                var info = Settings.Get(Name + " Login");

                if (!CanLogin || string.IsNullOrWhiteSpace(info) || _cts.IsCancellationRequested)
                {
                    SubtitleSearchDone.Fire(this);
                    return;
                }

                Log.Debug("Trying to authenticate with " + Name + "...");

                try
                {
                    _cts.Token.ThrowIfCancellationRequested();

                    var usrpwd  = Utils.Decrypt(this, info);
                    var cookies = Login(usrpwd[0], usrpwd[1]);

                    Cookies = cookies;
                    Settings.Set(Name + " Cookies", Utils.Encrypt(this, cookies));

                    _cts.Token.ThrowIfCancellationRequested();
                    var list = Search((string)query);
                    _cts.Token.ThrowIfCancellationRequested();

                    foreach (var link in list)
                    {
                        _cts.Token.ThrowIfCancellationRequested();
                        SubtitleSearchNewLink.Fire(this, link);
                        _cts.Token.ThrowIfCancellationRequested();
                    }

                    _cts.Token.ThrowIfCancellationRequested();
                    SubtitleSearchDone.Fire(this);
                }
                catch (InvalidCredentialException)
                {
                    Log.Warn("Failed to authenticate with " + Name + ": invalid credentials or broken plugin.");
                    SubtitleSearchDone.Fire(this);
                }
                catch (Exception ex)
                {
                    SubtitleSearchError.Fire(this, "There was an error while searching for subtitles.", ex);
                }
            }
            catch (Exception ex)
            {
                SubtitleSearchError.Fire(this, "There was an error while searching for subtitles.", ex);
            }
        }