private async Task ProcessJobItem(SyncJobItem jobItem, bool enableConversion, IProgress <double> progress, CancellationToken cancellationToken) { if (jobItem == null) { throw new ArgumentNullException("jobItem"); } var item = _libraryManager.GetItemById(jobItem.ItemId); if (item == null) { jobItem.Status = SyncJobItemStatus.Failed; _logger.Error("Unable to locate library item for JobItem {0}, ItemId {1}", jobItem.Id, jobItem.ItemId); await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.Progress = 0; var job = _syncManager.GetJob(jobItem.JobId); if (job == null) { _logger.Error("Job not found. Cannot complete the sync job."); await _syncManager.CancelJobItem(jobItem.Id).ConfigureAwait(false); return; } var user = _userManager.GetUserById(job.UserId); if (user == null) { jobItem.Status = SyncJobItemStatus.Failed; _logger.Error("User not found. Cannot complete the sync job."); await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } // See if there's already another active job item for the same target var existingJobItems = _syncManager.GetJobItems(new SyncJobItemQuery { AddMetadata = false, ItemId = jobItem.ItemId, TargetId = jobItem.TargetId, Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring } }); var duplicateJobItems = existingJobItems.Items .Where(i => !string.Equals(i.Id, jobItem.Id, StringComparison.OrdinalIgnoreCase)) .ToList(); if (duplicateJobItems.Count > 0) { var syncProvider = _syncManager.GetSyncProvider(jobItem) as IHasDuplicateCheck; if (!duplicateJobItems.Any(i => AllowDuplicateJobItem(syncProvider, i, jobItem))) { _logger.Debug("Cancelling sync job item because there is already another active job for the same target."); jobItem.Status = SyncJobItemStatus.Cancelled; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } } var syncOptions = _config.GetSyncOptions(); var video = item as Video; if (video != null) { await Sync(jobItem, video, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Audio) { await Sync(jobItem, (Audio)item, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Photo) { await Sync(jobItem, (Photo)item, cancellationToken).ConfigureAwait(false); } else { await SyncGeneric(jobItem, item, cancellationToken).ConfigureAwait(false); } }