Inheritance: IDisposable
        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
        {
            //Is retDays 0.. If So Exit...
            int retDays;

            if (!(Int32.TryParse(Plugin.Instance.Configuration.RetDays, out retDays))) {
                _logger.Info("Emby.Kodi.SyncQueue.Task: Retention Deletion Not Possible When Retention Days = 0!");
                return;
            }

            if (retDays == 0)
            {
                _logger.Info("Emby.Kodi.SyncQueue.Task: Retention Deletion Not Possible When Retention Days = 0!");
                return;
            }

            //Check Database
            bool result = await Task.Run(() =>
            {
                retDays = retDays * -1;
                var dt = DateTime.UtcNow.AddDays(retDays);
                var dtl = (long)(dt.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds);
                //DbRepo.DeleteOldData(dtl, _logger);

                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger))
                {                    
                    repo.DeleteOldData(dtl);
                }

                    return true;
            });
        }
        //private DataHelper dataHelper;

        public SyncAPI(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths applicationPaths, IUserManager userManager, ILibraryManager libraryManager)
        {
            _logger = logger;
            _jsonSerializer = jsonSerializer;
            _applicationPaths = applicationPaths;
            _userManager = userManager;
            _libraryManager = libraryManager;

            _logger.Info("Emby.Kodi.SyncQueue:  SyncAPI Created and Listening at \"/Emby.Kodi.SyncQueue/{UserID}/{LastUpdateDT}/GetItems?format=json\" - {LastUpdateDT} must be a UTC DateTime formatted as yyyy-MM-ddTHH:mm:ssZ");
            _logger.Info("Emby.Kodi.SyncQueue:  SyncAPI Created and Listening at \"/Emby.Kodi.SyncQueue/{UserID}/GetItems?LastUpdateDT={LastUpdateDT}&format=json\" - {LastUpdateDT} must be a UTC DateTime formatted as yyyy-MM-ddTHH:mm:ssZ");
            _logger.Info("Emby.Kodi.SyncQueue:  The following parameters also exist to filter the results:");
            _logger.Info("Emby.Kodi.SyncQueue:  filter=movies,tvshows,music,musicvideos,boxsets");
            _logger.Info("Emby.Kodi.SyncQueue:  Results will be included by default and only filtered if added to the filter query...");
            _logger.Info("Emby.Kodi.SyncQueue:  the filter query must be lowercase in both the name and the items...");

            ////repo = new DbRepo(_applicationPaths.DataPath);     
            using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
            {

            }
        }
        public async Task<SyncUpdateInfo> PopulateLibraryInfo(string userId, string lastDT, 
                                                              bool movies, bool tvshows, bool music,
                                                              bool musicvideos, bool boxsets)
        {
            var startTime = DateTime.UtcNow;

            _logger.Debug("Emby.Kodi.SyncQueue:  Starting PopulateLibraryInfo...");
            var userDataChangedJson = new List<string>();
            var tmpList = new List<string>();

            var info = new SyncUpdateInfo();

            //var userDT = Convert.ToDateTime(lastDT);
            var userDT = DateTime.Parse(lastDT, CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal);

            var dtl = (long)(userDT.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds);

            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting Items Added Info...");
            Task<List<string>> t1 = Task.Run(() =>
            {
                List<string> result = null;
                List<Guid> data = null;

                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
                {
                    data = repo.GetItems(dtl, 0, movies, tvshows, music, musicvideos, boxsets);
                }

                var user = _userManager.GetUserById(Guid.Parse(userId));

                List<BaseItem> items = new List<BaseItem>();
                data.ForEach(i =>
                {
                    var item = _libraryManager.GetItemById(i);
                    if (item != null)
                    {
                        items.Add(item);
                    }
                });

                result = items.SelectMany(i => ApiUserCheck.TranslatePhysicalItemToUserLibrary(i, user, _libraryManager)).Select(i => i.Id.ToString("N")).Distinct().ToList();
                
                if (result.Count > 0)
                {
                    _logger.Info(String.Format("Emby.Kodi.SyncQueue:  Added Items Found: {0}", string.Join(",", result.ToArray())));
                }
                else
                {
                    _logger.Info("Emby.Kodi.SyncQueue:  No Added Items Found!");
                }
                return result;
            });

            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting Items Removed Info...");
            Task<List<string>> t2 = Task.Run(() =>
            {
                List<string> result = new List<string>();
                List<Guid> data = null;

                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
                {
                    data = repo.GetItems(dtl, 2, movies, tvshows, music, musicvideos, boxsets);
                }

                //var user = _userManager.GetUserById(Guid.Parse(userId));

                //List<BaseItem> items = new List<BaseItem>();
                //data.ForEach(i =>
                //{
                //    var item = _libraryManager.GetItemById(i);
                //    if (item != null)
                //    {
                //        items.Add(item);
                //    }
                //});

                if (data != null && data.Count() > 0)
                {
                    data.ForEach(i =>
                    {
                        result.Add(i.ToString("N"));
                    });
                }

                //result = items.SelectMany(i => ApiUserCheck.TranslatePhysicalItemToUserLibrary(i, user, _libraryManager, true)).Select(i => i.Id.ToString("N")).Distinct().ToList();

                if (result.Count > 0)
                {
                    _logger.Info(String.Format("Emby.Kodi.SyncQueue:  Removed Items Found: {0}", string.Join(",", result.ToArray())));
                }
                else
                {
                    _logger.Info("Emby.Kodi.SyncQueue:  No Removed Items Found!");
                }
                return result;
            });

            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting Items Updated Info...");
            Task<List<string>> t3 = Task.Run(() =>
            {
                List<string> result = null;
                List<Guid> data = null;

                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
                {
                    data = repo.GetItems(dtl, 1, movies, tvshows, music, musicvideos, boxsets);
                }

                var user = _userManager.GetUserById(Guid.Parse(userId));

                List<BaseItem> items = new List<BaseItem>();
                data.ForEach(i =>
                {
                    var item = _libraryManager.GetItemById(i);
                    if (item != null)
                    {
                        items.Add(item);
                    }
                });

                result = items.SelectMany(i => ApiUserCheck.TranslatePhysicalItemToUserLibrary(i, user, _libraryManager)).Select(i => i.Id.ToString("N")).Distinct().ToList();


                if (result.Count > 0)
                {
                    _logger.Info(String.Format("Emby.Kodi.SyncQueue:  Updated Items Found: {0}", string.Join(",", result.ToArray())));
                }
                else
                {
                    _logger.Info("Emby.Kodi.SyncQueue:  No Updated Items Found!");
                }
                return result;
            });

            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting Folders Added To Info...");
            info.FoldersAddedTo.Clear();
            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting Folders Removed From Info...");
            info.FoldersRemovedFrom.Clear();
            _logger.Debug("Emby.Kodi.SyncQueue:  PopulateLibraryInfo:  Getting User Data Changed Info...");
            Task<List<string>> t4 = Task.Run(() =>
            {
                List<UserJson> data = null;          
                List<string> result = null;
                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger))
                {
                    data = repo.GetUserInfos(dtl, userId, movies, tvshows, music, musicvideos, boxsets);
                }

                result = data.Select(i => i.JsonData).ToList();

                if (result.Count > 0)
                {
                    _logger.Info(String.Format("Emby.Kodi.SyncQueue:  User Data Changed Info Found: {0}", string.Join(",", data.Select(i => i.Id).ToArray())));
                }
                else
                {
                    _logger.Info("Emby.Kodi.SyncQueue:  No User Data Changed Info Found!");
                }
                
                return result;
            });

            await Task.WhenAll(t1, t2, t3, t4);

            info.ItemsAdded = t1.Result;
            info.ItemsRemoved = t2.Result;
            info.ItemsUpdated = t3.Result;
            userDataChangedJson = t4.Result;

            info.UserDataChanged = userDataChangedJson.Select(i => _jsonSerializer.DeserializeFromString<UserItemDataDto>(i)).ToList();

            TimeSpan diffDate = DateTime.UtcNow - startTime;
            _logger.Info(String.Format("Emby.Kodi.SyncQueue: Request Finished Taking {0}", diffDate.ToString("c")));

            return info;
        }
        public async Task UpdateLibrary(List<LibItem> Items, string tableName, int status, CancellationToken cancellationToken)
        {
            var statusType = string.Empty;
            if (status == 0) { statusType = "Added"; }
            else if (status == 1) { statusType = "Updated"; }
            else { statusType = "Removed"; }

            bool result = await Task.Run(() =>
            {
                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
                {
                    repo.WriteLibrarySync(Items, status, cancellationToken);
                }
                return true;
            });

            _logger.Info(String.Format("Emby.Kodi.SyncQueue: \"LIBRARYSYNC\" {0} {1} items:  {2}", statusType, Items.Count(),
                String.Join(",", Items.Select(i => i.Id.ToString("N")).ToArray())));
        }
        private async Task SaveUserChanges(List<MediaBrowser.Model.Dto.UserItemDataDto> dtos, List<LibItem> itemRefs, string userName, string userId, CancellationToken cancellationToken)
        {
            bool result = await Task.Run(() =>
            {
                using (var repo = new DbRepo(_applicationPaths.DataPath, _logger, _jsonSerializer))
                {
                    repo.SetUserInfoSync(dtos, itemRefs, userName, userId, cancellationToken);
                }
                return true;
            });
            
            List<string> ids = dtos.Select(s => s.ItemId).ToList();

            _logger.Info(String.Format("Emby.Kodi.SyncQueue: \"USERSYNC\" User {0}({1}) posted {2} Updates:  {3}", userId, userName, ids.Count(), String.Join(",", ids.ToArray())));
        }