public async Task EnsureJobItems(SyncJob job) { var user = _userManager.GetUserById(job.UserId); if (user == null) { throw new InvalidOperationException("Cannot proceed with sync because user no longer exists."); } var items = (await GetItemsForSync(job.Category, job.ParentId, job.RequestedItemIds, user, job.UnwatchedOnly).ConfigureAwait(false)) .ToList(); var jobItems = _syncRepo.GetJobItems(new SyncJobItemQuery { JobId = job.Id }).Items.ToList(); foreach (var item in items) { // Respect ItemLimit, if set if (job.ItemLimit.HasValue) { if (jobItems.Count(j => j.Status != SyncJobItemStatus.RemovedFromDevice && j.Status != SyncJobItemStatus.Failed) >= job.ItemLimit.Value) { break; } } var itemId = item.Id.ToString("N"); var jobItem = jobItems.FirstOrDefault(i => string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase)); if (jobItem != null) { continue; } jobItem = new SyncJobItem { Id = Guid.NewGuid().ToString("N"), ItemId = itemId, ItemName = GetSyncJobItemName(item), JobId = job.Id, TargetId = job.TargetId, DateCreated = DateTime.UtcNow }; await _syncRepo.Create(jobItem).ConfigureAwait(false); jobItems.Add(jobItem); } jobItems = jobItems .OrderBy(i => i.DateCreated) .ToList(); await UpdateJobStatus(job, jobItems).ConfigureAwait(false); }
public static Task<SyncDialogOptions> GetSyncOptions(this IApiClient apiClient, SyncJob job) { return apiClient.GetSyncOptions(new SyncJobRequest { Category = job.Category, ItemIds = job.RequestedItemIds, ParentId = job.ParentId, TargetId = job.TargetId, UserId = job.UserId }); }
public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request) { var items = GetItemsForSync(request.ItemIds).ToList(); if (items.Count == 1) { request.Name = GetDefaultName(items[0]); } if (string.IsNullOrWhiteSpace(request.Name)) { throw new ArgumentException("Please supply a name for the sync job."); } var target = GetSyncTargets(request.UserId) .First(i => string.Equals(request.TargetId, i.Id)); var jobId = Guid.NewGuid().ToString("N"); var job = new SyncJob { Id = jobId, Name = request.Name, TargetId = target.Id, UserId = request.UserId, UnwatchedOnly = request.UnwatchedOnly, Limit = request.Limit, LimitType = request.LimitType, RequestedItemIds = request.ItemIds, DateCreated = DateTime.UtcNow, DateLastModified = DateTime.UtcNow, ItemCount = 1 }; await _repo.Create(job).ConfigureAwait(false); return new SyncJobCreationResult { Job = GetJob(jobId) }; }
private Task UpdateJobStatus(SyncJob job, List<SyncJobItem> jobItems) { job.ItemCount = jobItems.Count; double pct = 0; foreach (var item in jobItems) { if (item.Status == SyncJobItemStatus.Failed || item.Status == SyncJobItemStatus.Synced || item.Status == SyncJobItemStatus.RemovedFromDevice) { pct += 100; } else { pct += item.Progress ?? 0; } } if (job.ItemCount > 0) { pct /= job.ItemCount; job.Progress = pct; } else { job.Progress = null; } if (pct >= 100) { if (jobItems.Any(i => i.Status == SyncJobItemStatus.Failed)) { job.Status = SyncJobStatus.CompletedWithError; } else { job.Status = SyncJobStatus.Completed; } } else if (pct.Equals(0)) { job.Status = SyncJobStatus.Queued; } else { job.Status = SyncJobStatus.InProgress; } return _syncRepo.Update(job); }
public async Task Update(SyncJob job) { if (job == null) { throw new ArgumentNullException("job"); } await _writeLock.WaitAsync().ConfigureAwait(false); IDbTransaction transaction = null; try { transaction = _connection.BeginTransaction(); var index = 0; _saveJobCommand.GetParameter(index++).Value = new Guid(job.Id); _saveJobCommand.GetParameter(index++).Value = job.TargetId; _saveJobCommand.GetParameter(index++).Value = job.Name; _saveJobCommand.GetParameter(index++).Value = job.Quality; _saveJobCommand.GetParameter(index++).Value = job.Status; _saveJobCommand.GetParameter(index++).Value = job.Progress; _saveJobCommand.GetParameter(index++).Value = job.UserId; _saveJobCommand.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray()); _saveJobCommand.GetParameter(index++).Value = job.UnwatchedOnly; _saveJobCommand.GetParameter(index++).Value = job.Limit; _saveJobCommand.GetParameter(index++).Value = job.LimitType; _saveJobCommand.GetParameter(index++).Value = job.IsDynamic; _saveJobCommand.GetParameter(index++).Value = job.DateCreated; _saveJobCommand.GetParameter(index++).Value = job.DateLastModified; _saveJobCommand.GetParameter(index++).Value = job.ItemCount; _saveJobCommand.Transaction = transaction; _saveJobCommand.ExecuteNonQuery(); transaction.Commit(); } catch (OperationCanceledException) { if (transaction != null) { transaction.Rollback(); } throw; } catch (Exception e) { _logger.ErrorException("Failed to save record:", e); if (transaction != null) { transaction.Rollback(); } throw; } finally { if (transaction != null) { transaction.Dispose(); } _writeLock.Release(); } }
private Task UpdateJobStatus(SyncJob job) { if (job == null) { throw new ArgumentNullException("job"); } var result = _syncRepo.GetJobItems(new SyncJobItemQuery { JobId = job.Id }); return UpdateJobStatus(job, result.Items.ToList()); }
private async Task ProcessJobItem(SyncJob job, SyncJobItem jobItem, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken) { 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 syncOptions = _config.GetSyncOptions(); 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 = job.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, job) 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 video = item as Video; if (video != null) { await Sync(jobItem, job, video, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Audio) { await Sync(jobItem, job, (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); } }
public Task Create(SyncJob job) { return Update(job); }
public SyncJobOptions GetAudioOptions(SyncJobItem jobItem, SyncJob job) { var options = GetSyncJobOptions(jobItem.TargetId, null, null); if (job.Bitrate.HasValue) { options.DeviceProfile.MaxStaticBitrate = job.Bitrate.Value; } return options; }
public SyncJobOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job) { var options = GetSyncJobOptions(jobItem.TargetId, job.Profile, job.Quality); if (job.Bitrate.HasValue) { options.DeviceProfile.MaxStaticBitrate = job.Bitrate.Value; } return options; }
public SyncJobViewModel(SyncJob syncJob, INavigationService navigationService, IConnectionManager connectionManager, SyncViewModel syncViewModel) : base(navigationService, connectionManager) { _syncViewModel = syncViewModel; SyncJob = syncJob; }
private SyncJob GetJob(IDataReader reader) { var info = new SyncJob { Id = reader.GetGuid(0).ToString("N"), TargetId = reader.GetString(1), Name = reader.GetString(2) }; if (!reader.IsDBNull(3)) { info.Quality = (SyncQuality)Enum.Parse(typeof(SyncQuality), reader.GetString(3), true); } if (!reader.IsDBNull(4)) { info.Status = (SyncJobStatus)Enum.Parse(typeof(SyncJobStatus), reader.GetString(4), true); } if (!reader.IsDBNull(5)) { info.Progress = reader.GetDouble(5); } if (!reader.IsDBNull(6)) { info.UserId = reader.GetString(6); } if (!reader.IsDBNull(7)) { info.RequestedItemIds = reader.GetString(7).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } if (!reader.IsDBNull(8)) { info.Category = (SyncCategory)Enum.Parse(typeof(SyncCategory), reader.GetString(8), true); } if (!reader.IsDBNull(9)) { info.ParentId = reader.GetString(9); } if (!reader.IsDBNull(10)) { info.UnwatchedOnly = reader.GetBoolean(10); } if (!reader.IsDBNull(11)) { info.ItemLimit = reader.GetInt32(11); } info.SyncNewContent = reader.GetBoolean(12); info.DateCreated = reader.GetDateTime(13).ToUniversalTime(); info.DateLastModified = reader.GetDateTime(14).ToUniversalTime(); info.ItemCount = reader.GetInt32(15); return info; }
public LocalItem CreateLocalItem(IServerSyncProvider provider, SyncedItem syncedItem, SyncJob job, SyncTarget target, BaseItemDto libraryItem, string serverId, string serverName, string originalFileName) { var path = GetDirectoryPath(provider, job, syncedItem, libraryItem, serverName); path.Add(GetLocalFileName(provider, libraryItem, originalFileName)); var localPath = string.Join(PathSeparatorString, path.ToArray()); foreach (var mediaSource in libraryItem.MediaSources) { mediaSource.Path = localPath; mediaSource.Protocol = MediaProtocol.File; } return new LocalItem { Item = libraryItem, ItemId = libraryItem.Id, ServerId = serverId, LocalPath = localPath, Id = GetLocalId(syncedItem.SyncJobItemId, libraryItem.Id), SyncJobItemId = syncedItem.SyncJobItemId }; }
private List<string> GetDirectoryPath(IServerSyncProvider provider, SyncJob job, SyncedItem syncedItem, BaseItemDto item, string serverName) { var parts = new List<string> { serverName }; var profileOption = _syncManager.GetProfileOptions(job.TargetId) .FirstOrDefault(i => string.Equals(i.Id, job.Profile, StringComparison.OrdinalIgnoreCase)); string name; if (profileOption != null && !string.IsNullOrWhiteSpace(profileOption.Name)) { name = profileOption.Name; if (job.Bitrate.HasValue) { name += "-" + job.Bitrate.Value.ToString(CultureInfo.InvariantCulture); } else { var qualityOption = _syncManager.GetQualityOptions(job.TargetId) .FirstOrDefault(i => string.Equals(i.Id, job.Quality, StringComparison.OrdinalIgnoreCase)); if (qualityOption != null && !string.IsNullOrWhiteSpace(qualityOption.Name)) { name += "-" + qualityOption.Name; } } } else { name = syncedItem.SyncJobName + "-" + syncedItem.SyncJobDateCreated .ToLocalTime() .ToString("g") .Replace(" ", "-"); } name = GetValidFilename(provider, name); parts.Add(name); if (item.IsType("episode")) { parts.Add("TV"); if (!string.IsNullOrWhiteSpace(item.SeriesName)) { parts.Add(item.SeriesName); } } else if (item.IsVideo) { parts.Add("Videos"); parts.Add(item.Name); } else if (item.IsAudio) { parts.Add("Music"); if (!string.IsNullOrWhiteSpace(item.AlbumArtist)) { parts.Add(item.AlbumArtist); } if (!string.IsNullOrWhiteSpace(item.Album)) { parts.Add(item.Album); } } else if (string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase)) { parts.Add("Photos"); if (!string.IsNullOrWhiteSpace(item.Album)) { parts.Add(item.Album); } } return parts.Select(i => GetValidFilename(provider, i)).ToList(); }
public string GetTemporaryPath(SyncJob job) { return GetTemporaryPath(job.Id); }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetAudioOptions(jobItem, job); var conversionOptions = new AudioOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting) { if (!enableConversion) { return; } jobItem.Status = SyncJobItemStatus.Converting; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, false).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetVideoOptions(jobItem, job); var conversionOptions = new VideoOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions); var mediaSource = streamInfo.MediaSource; // No sense creating external subs if we're already burning one into the video var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ? new List<SubtitleStreamInfo>() : streamInfo.GetExternalSubtitles(false, true, null, null); // Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting; var requiresConversion = requiresVideoTranscoding || externalSubs.Any(i => RequiresExtraction(i, mediaSource)); if (requiresConversion && !enableConversion) { return; } jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (requiresConversion) { jobItem.Status = SyncJobItemStatus.Converting; } if (requiresVideoTranscoding) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit, ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, true).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; if (externalSubs.Count > 0) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await ConvertSubtitles(jobItem, externalSubs, streamInfo, cancellationToken).ConfigureAwait(false); } jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request) { var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager); var user = _userManager.GetUserById(request.UserId); var items = processor .GetItemsForSync(request.ItemIds, user, request.UnwatchedOnly) .ToList(); if (items.Any(i => !SupportsSync(i))) { throw new ArgumentException("Item does not support sync."); } if (string.IsNullOrWhiteSpace(request.Name) && request.ItemIds.Count == 1) { request.Name = GetDefaultName(_libraryManager.GetItemById(request.ItemIds[0])); } if (string.IsNullOrWhiteSpace(request.Name)) { throw new ArgumentException("Please supply a name for the sync job."); } var target = GetSyncTargets(request.UserId) .First(i => string.Equals(request.TargetId, i.Id)); var jobId = Guid.NewGuid().ToString("N"); var job = new SyncJob { Id = jobId, Name = request.Name, TargetId = target.Id, UserId = request.UserId, UnwatchedOnly = request.UnwatchedOnly, ItemLimit = request.ItemLimit, RequestedItemIds = request.ItemIds, DateCreated = DateTime.UtcNow, DateLastModified = DateTime.UtcNow, SyncNewContent = request.SyncNewContent, ItemCount = items.Count, Quality = request.Quality, Category = request.Category, ParentId = request.ParentId }; // It's just a static list if (!items.Any(i => i.IsFolder || i is IItemByName)) { job.SyncNewContent = false; } await _repo.Create(job).ConfigureAwait(false); await processor.EnsureJobItems(job).ConfigureAwait(false); return new SyncJobCreationResult { Job = GetJob(jobId) }; }
internal void OnSyncJobUpdated(SyncJob job) { if (SyncJobUpdated != null) { EventHelper.FireEventIfNotNull(SyncJobUpdated, this, new GenericEventArgs<SyncJob> { Argument = job }, _logger); } }
public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request) { var processor = GetSyncJobProcessor(); var user = _userManager.GetUserById(request.UserId); var items = (await processor .GetItemsForSync(request.Category, request.ParentId, request.ItemIds, user, request.UnwatchedOnly).ConfigureAwait(false)) .ToList(); if (items.Any(i => !SupportsSync(i))) { throw new ArgumentException("Item does not support sync."); } if (string.IsNullOrWhiteSpace(request.Name)) { if (request.ItemIds.Count == 1) { request.Name = GetDefaultName(_libraryManager.GetItemById(request.ItemIds[0])); } } if (string.IsNullOrWhiteSpace(request.Name)) { request.Name = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString(); } var target = GetSyncTargets(request.UserId) .FirstOrDefault(i => string.Equals(request.TargetId, i.Id)); if (target == null) { throw new ArgumentException("Sync target not found."); } var jobId = Guid.NewGuid().ToString("N"); if (string.IsNullOrWhiteSpace(request.Quality)) { request.Quality = GetQualityOptions(request.TargetId) .Where(i => i.IsDefault) .Select(i => i.Id) .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } var job = new SyncJob { Id = jobId, Name = request.Name, TargetId = target.Id, UserId = request.UserId, UnwatchedOnly = request.UnwatchedOnly, ItemLimit = request.ItemLimit, RequestedItemIds = request.ItemIds ?? new List<string> { }, DateCreated = DateTime.UtcNow, DateLastModified = DateTime.UtcNow, SyncNewContent = request.SyncNewContent, ItemCount = items.Count, Category = request.Category, ParentId = request.ParentId, Quality = request.Quality, Profile = request.Profile, Bitrate = request.Bitrate }; if (!request.Category.HasValue && request.ItemIds != null) { var requestedItems = request.ItemIds .Select(_libraryManager.GetItemById) .Where(i => i != null); // It's just a static list if (!requestedItems.Any(i => i.IsFolder || i is IItemByName)) { job.SyncNewContent = false; } } await _repo.Create(job).ConfigureAwait(false); await processor.EnsureJobItems(job).ConfigureAwait(false); // If it already has a converting status then is must have been aborted during conversion var jobItemsResult = GetJobItems(new SyncJobItemQuery { Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting }, JobId = jobId, AddMetadata = false }); await processor.SyncJobItems(jobItemsResult.Items, false, new Progress<double>(), CancellationToken.None) .ConfigureAwait(false); jobItemsResult = GetJobItems(new SyncJobItemQuery { Statuses = new[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting }, JobId = jobId, AddMetadata = false }); var returnResult = new SyncJobCreationResult { Job = GetJob(jobId), JobItems = jobItemsResult.Items.ToList() }; if (SyncJobCreated != null) { EventHelper.FireEventIfNotNull(SyncJobCreated, this, new GenericEventArgs<SyncJobCreationResult> { Argument = returnResult }, _logger); } if (returnResult.JobItems.Any(i => i.Status == SyncJobItemStatus.Queued || i.Status == SyncJobItemStatus.Converting)) { _taskManager.QueueScheduledTask<SyncConvertScheduledTask>(); } return returnResult; }
public void ProcessJobItem(SyncJob job, SyncJobItem jobItem, SyncTarget target) { }
public ISyncProvider GetSyncProvider(SyncJobItem jobItem, SyncJob job) { foreach (var provider in _providers) { foreach (var target in GetSyncTargets(provider)) { if (string.Equals(target.Id, jobItem.TargetId, StringComparison.OrdinalIgnoreCase)) { return provider; } } } return null; }
private SyncJob GetJob(IDataReader reader) { var info = new SyncJob { Id = reader.GetGuid(0).ToString("N"), TargetId = reader.GetString(1), Name = reader.GetString(2) }; if (!reader.IsDBNull(3)) { info.Quality = (SyncQuality)Enum.Parse(typeof(SyncQuality), reader.GetString(3), true); } if (!reader.IsDBNull(4)) { info.Status = (SyncJobStatus)Enum.Parse(typeof(SyncJobStatus), reader.GetString(4), true); } if (!reader.IsDBNull(5)) { info.Progress = reader.GetDouble(5); } if (!reader.IsDBNull(6)) { info.UserId = reader.GetString(6); } if (!reader.IsDBNull(7)) { info.RequestedItemIds = reader.GetString(7).Split(',').ToList(); } if (!reader.IsDBNull(8)) { info.UnwatchedOnly = reader.GetBoolean(8); } if (!reader.IsDBNull(9)) { info.Limit = reader.GetInt64(9); } if (!reader.IsDBNull(10)) { info.LimitType = (SyncLimitType)Enum.Parse(typeof(SyncLimitType), reader.GetString(10), true); } info.IsDynamic = reader.GetBoolean(11); info.DateCreated = reader.GetDateTime(12).ToUniversalTime(); info.DateLastModified = reader.GetDateTime(13).ToUniversalTime(); info.ItemCount = reader.GetInt32(14); return info; }
public async Task UpdateJob(SyncJob job) { // Get fresh from the db and only update the fields that are supported to be changed. var instance = _repo.GetJob(job.Id); instance.Name = job.Name; instance.Quality = job.Quality; instance.Profile = job.Profile; instance.UnwatchedOnly = job.UnwatchedOnly; instance.SyncNewContent = job.SyncNewContent; instance.ItemLimit = job.ItemLimit; await _repo.Update(instance).ConfigureAwait(false); OnSyncJobUpdated(instance); }
private async Task UpdateJobStatus(SyncJob job, List<SyncJobItem> jobItems) { job.ItemCount = jobItems.Count; double pct = 0; foreach (var item in jobItems) { if (item.Status == SyncJobItemStatus.Failed || item.Status == SyncJobItemStatus.Synced || item.Status == SyncJobItemStatus.RemovedFromDevice || item.Status == SyncJobItemStatus.Cancelled) { pct += 100; } else { pct += item.Progress ?? 0; } } if (job.ItemCount > 0) { pct /= job.ItemCount; job.Progress = pct; } else { job.Progress = null; } if (jobItems.All(i => i.Status == SyncJobItemStatus.Queued)) { job.Status = SyncJobStatus.Queued; } else if (jobItems.All(i => i.Status == SyncJobItemStatus.Failed)) { job.Status = SyncJobStatus.Failed; } else if (jobItems.All(i => i.Status == SyncJobItemStatus.Cancelled)) { job.Status = SyncJobStatus.Cancelled; } else if (jobItems.All(i => i.Status == SyncJobItemStatus.ReadyToTransfer)) { job.Status = SyncJobStatus.ReadyToTransfer; } else if (jobItems.All(i => i.Status == SyncJobItemStatus.Transferring)) { job.Status = SyncJobStatus.Transferring; } else if (jobItems.Any(i => i.Status == SyncJobItemStatus.Converting)) { job.Status = SyncJobStatus.Converting; } else if (jobItems.All(i => i.Status == SyncJobItemStatus.Cancelled || i.Status == SyncJobItemStatus.Failed || i.Status == SyncJobItemStatus.Synced || i.Status == SyncJobItemStatus.RemovedFromDevice)) { if (jobItems.Any(i => i.Status == SyncJobItemStatus.Failed)) { job.Status = SyncJobStatus.CompletedWithError; } else { job.Status = SyncJobStatus.Completed; } } else { job.Status = SyncJobStatus.Queued; } await _syncRepo.Update(job).ConfigureAwait(false); _syncManager.OnSyncJobUpdated(job); }
private async Task FillMetadata(SyncJob job) { var user = _userManager.GetUserById(job.UserId); if (user == null) { return; } var target = GetSyncTargets(job.UserId) .FirstOrDefault(i => string.Equals(i.Id, job.TargetId, StringComparison.OrdinalIgnoreCase)); if (target != null) { job.TargetName = target.Name; } var item = job.RequestedItemIds .Select(_libraryManager.GetItemById) .FirstOrDefault(i => i != null); if (item == null) { var processor = GetSyncJobProcessor(); item = (await processor .GetItemsForSync(job.Category, job.ParentId, job.RequestedItemIds, user, job.UnwatchedOnly).ConfigureAwait(false)) .FirstOrDefault(); } if (item != null) { var hasSeries = item as IHasSeries; if (hasSeries != null) { job.ParentName = hasSeries.SeriesName; } var hasAlbumArtist = item as IHasAlbumArtist; if (hasAlbumArtist != null) { job.ParentName = hasAlbumArtist.AlbumArtists.FirstOrDefault(); } var primaryImage = item.GetImageInfo(ImageType.Primary, 0); var itemWithImage = item; if (primaryImage == null) { var parentWithImage = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary)); if (parentWithImage != null) { itemWithImage = parentWithImage; primaryImage = parentWithImage.GetImageInfo(ImageType.Primary, 0); } } if (primaryImage != null) { try { job.PrimaryImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Primary); job.PrimaryImageItemId = itemWithImage.Id.ToString("N"); } catch (Exception ex) { _logger.ErrorException("Error getting image info", ex); } } } }
private void FillMetadata(SyncJob job) { var item = GetItemsForSync(job.RequestedItemIds) .FirstOrDefault(); if (item != null) { var hasSeries = item as IHasSeries; if (hasSeries != null) { job.ParentName = hasSeries.SeriesName; } var hasAlbumArtist = item as IHasAlbumArtist; if (hasAlbumArtist != null) { job.ParentName = hasAlbumArtist.AlbumArtists.FirstOrDefault(); } var primaryImage = item.GetImageInfo(ImageType.Primary, 0); if (primaryImage != null) { try { job.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); job.PrimaryImageItemId = item.Id.ToString("N"); } catch (Exception ex) { _logger.ErrorException("Error getting image info", ex); } } } }