/// <summary>
        /// Update the watched media with the data saved in the JSON files.
        /// </summary>
        /// <param name="otherServerMedia">The other server's media information to compare with</param>
        /// <param name="kodiApi">The object containing the API details</param>
        public void CompareAndUpdateAPIData(ServerMedia otherServerMedia, KodiApi kodiApi)
        {
            List <string> processedFiles = new List <string>();

            if (this.HasResults && otherServerMedia.HasResults)
            {
                Utilities.Message("Syncing {0} watched media", kodiApi.Name);

                // compare and format data
                List <Movie> otherMovies   = otherServerMedia.MovieResult.Result.Movies;
                List <Movie> missingMovies = this.MovieResult.Result.Movies.Except(otherMovies, new KodiMovieEqualityComparer()).ToList();

                foreach (Movie movie in missingMovies)
                {
                    movie.Update(otherMovies, x => x.Label == movie.Label && x.Year == movie.Year);
                }

                this.MismatchMessage <Movie>(missingMovies, "movie", false);

                // send data to API
                foreach (Movie movie in missingMovies.Where(x => x.IsOutDated))
                {
                    this.UpdateMedia <MovieResult>(kodiApi, movie.MovieId, movie.IsOutDatedResumePosition, movie.IsOutDatedWatched, movie.Resume.Position, movie.Playcount, string.Format("{0} {1}", movie.Label, movie.Year), processedFiles);
                }

                // compare and format data
                List <Episode> otherEpisodes   = otherServerMedia.EpisodeResult.Result.Episodes;
                List <Episode> missingEpisodes = this.EpisodeResult.Result.Episodes.Except(otherEpisodes, new KodiEpisodeEqualityComparer()).ToList();

                foreach (Episode episode in missingEpisodes)
                {
                    episode.Update(otherEpisodes, x => x.Label == episode.Label && x.ShowTitle == episode.ShowTitle);
                }

                this.MismatchMessage <Episode>(missingEpisodes, "episode", true);

                // send data to API
                foreach (Episode episode in missingEpisodes.Where(x => x.IsOutDated))
                {
                    this.UpdateMedia <EpisodesResult>(kodiApi, episode.EpisodeId, episode.IsOutDatedResumePosition, episode.IsOutDatedWatched, episode.Resume.Position, episode.Playcount, string.Format("{0} {1}", episode.ShowTitle, episode.Label), processedFiles);
                }
            }
            else if (!this.HasResults)
            {
                Utilities.Message("{0} has no results to sync", kodiApi.Name);
            }
            else if (!otherServerMedia.HasResults)
            {
                Utilities.Message("{0} has no results to sync with", kodiApi.Name);
            }

            // save list of changed values
            if (processedFiles.Count > 0)
            {
                this.SaveLogToFile(processedFiles);
            }
            Console.WriteLine("");
        }
        /// <summary>
        /// Access the API on the server and write the details of the media to the HDD
        /// </summary>
        /// <param name="kodiApi">The API class to use to interact with Kodi</param>
        /// <returns>A object containing the movie and episode data from the API</returns>
        public void ReadFromAPIAndSave(KodiApi kodiApi)
        {
            // make sure server is online
            bool serverOnline = Network.PingHost(kodiApi.ServerIP);

            Utilities.Message("Pinging server {0} {1}", kodiApi.ServerIP, (serverOnline) ? "succeeded" : "failed");

            if (serverOnline)
            {
                kodiApi.SetIsOnline();
                if (kodiApi.IsOnline)
                {
                    Utilities.Message("Reading media on {0} and saving to file", kodiApi.Name);

                    // get the media data from the API
                    this.MovieResult   = kodiApi.GetResults <MovieResult>();
                    this.EpisodeResult = kodiApi.GetResults <EpisodesResult>();

                    // make sure API requests worked
                    if (this.HasResults)
                    {
                        Utilities.Message(1, "Found {0} movie(s)", this.MovieResult.Result.Count);
                        Utilities.Message(2, "{0} watched", this.MovieResult.Result.CountWatched);
                        Utilities.Message(2, "{0} resumable", this.MovieResult.Result.CountResumable);
                        Utilities.Message(1, "Found {0} episode(s)", this.EpisodeResult.Result.Count);
                        Utilities.Message(2, "{0} watched", this.EpisodeResult.Result.CountWatched);
                        Utilities.Message(2, "{0} resumable", this.EpisodeResult.Result.CountResumable);

                        // write the media to the HDD
                        ServerMedia serverMedia = new ServerMedia(this.MovieResult, this.EpisodeResult);

                        string filePath      = serverMedia.FilePath(kodiApi.ServerIP);
                        string directoryPath = new FileInfo(filePath).Directory.FullName;

                        if (!Directory.Exists(directoryPath))
                        {
                            Directory.CreateDirectory(directoryPath);
                            Utilities.Message(1, "Directory {0} created to store media data", directoryPath);
                        }
                        serverMedia.SaveToFile(kodiApi.ServerIP);

                        Utilities.Message(1, "Saved media on {0} to {1}", kodiApi.Name, filePath);
                    }
                    else
                    {
                        Utilities.Message("API request to {0} failed using URL {1}", kodiApi.Name, kodiApi.ServerAPIURL);
                    }
                }
                else
                {
                    Utilities.Message("{0} API is offline", kodiApi.Name);
                }
            }

            Console.WriteLine("");
        }
        /// <summary>
        /// Read the watched json from the hdd
        /// </summary>
        /// <param name="serverIp">The server IP address used for he filename</param>
        private void ReadFromFile(string serverIp)
        {
            string listJson = string.Empty;

            if (File.Exists(this.FilePath(serverIp)))
            {
                using (StreamReader sr = new StreamReader(this.FilePath(serverIp)))
                {
                    listJson = sr.ReadToEnd();
                }

                ServerMedia watched = SimpleJson.DeserializeObject <ServerMedia>(listJson);
                if (watched != null)
                {
                    this.MovieResult   = watched.MovieResult;
                    this.EpisodeResult = watched.EpisodeResult;
                }
            }
        }
        public bool UpdateLibraries()
        {
            // set up API objects
            KodiApi kodiApi     = new KodiApi(Settings.Server1Name, Settings.Server1IP, Settings.Server1APIURL, Settings.Server1APIUsername, Settings.Server1APIPassword);
            KodiApi openElecApi = new KodiApi(Settings.Server2Name, Settings.Server2IP, Settings.Server2APIURL, Settings.Server2APIUsername, Settings.Server2APIPassword);

            // read api data and save to file
            ServerMedia kodiMedia = new ServerMedia();

            kodiMedia.ReadFromAPIAndSave(kodiApi);

            ServerMedia openelecMedia = new ServerMedia();

            openelecMedia.ReadFromAPIAndSave(openElecApi);

            // load historical unnwatched API data for inactive APIs
            if (!kodiApi.IsOnline && openElecApi.IsOnline)
            {
                kodiMedia.ReadFromHistoricFile(kodiApi);
            }
            if (kodiApi.IsOnline && !openElecApi.IsOnline)
            {
                openelecMedia.ReadFromHistoricFile(openElecApi);
            }

            // updated libraries based on active APIs
            if (kodiApi.IsOnline)
            {
                kodiMedia.CompareAndUpdateAPIData(openelecMedia, kodiApi);
            }
            if (openElecApi.IsOnline)
            {
                openelecMedia.CompareAndUpdateAPIData(kodiMedia, openElecApi);
            }


            // delay the console window close
            this.DelayConsoleClose(Settings.SecondsBeforeClose);
            return(false);
        }