internal async Task UpdateSyncJobItemInternal(SyncJobItem jobItem) { await _repo.Update(jobItem).ConfigureAwait(false); if (SyncJobUpdated != null) { EventHelper.FireEventIfNotNull(SyncJobItemUpdated, this, new GenericEventArgs <SyncJobItem> { Argument = jobItem }, _logger); } }
private async Task ProcessJobItem(SyncJob job, SyncJobItem jobItem, 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 _syncRepo.Update(jobItem).ConfigureAwait(false); return; } var deviceProfile = _syncManager.GetDeviceProfile(jobItem.TargetId); if (deviceProfile == null) { jobItem.Status = SyncJobItemStatus.Failed; _logger.Error("Unable to locate SyncTarget for JobItem {0}, SyncTargetId {1}", jobItem.Id, jobItem.TargetId); await _syncRepo.Update(jobItem).ConfigureAwait(false); return; } jobItem.Progress = 0; jobItem.Status = SyncJobItemStatus.Converting; var user = _userManager.GetUserById(job.UserId); var video = item as Video; if (video != null) { await Sync(jobItem, video, user, deviceProfile, progress, cancellationToken).ConfigureAwait(false); } else if (item is Audio) { await Sync(jobItem, (Audio)item, user, deviceProfile, progress, cancellationToken).ConfigureAwait(false); } else if (item is Photo) { await Sync(jobItem, (Photo)item, deviceProfile, cancellationToken).ConfigureAwait(false); } else { await SyncGeneric(jobItem, item, deviceProfile, cancellationToken).ConfigureAwait(false); } }
public ISyncProvider GetSyncProvider(SyncJobItem jobItem) { 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 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; } 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); } }
private SyncedItem GetJobItemInfo(SyncJobItem jobItem) { var job = _repo.GetJob(jobItem.JobId); var libraryItem = _libraryManager.GetItemById(jobItem.ItemId); var syncedItem = new SyncedItem { SyncJobId = jobItem.JobId, SyncJobItemId = jobItem.Id, ServerId = _appHost.SystemId, UserId = job.UserId }; var dtoOptions = new DtoOptions(); // Remove some bloat dtoOptions.Fields.Remove(ItemFields.MediaStreams); dtoOptions.Fields.Remove(ItemFields.IndexOptions); dtoOptions.Fields.Remove(ItemFields.MediaSourceCount); dtoOptions.Fields.Remove(ItemFields.OriginalPrimaryImageAspectRatio); dtoOptions.Fields.Remove(ItemFields.Path); dtoOptions.Fields.Remove(ItemFields.SeriesGenres); dtoOptions.Fields.Remove(ItemFields.Settings); dtoOptions.Fields.Remove(ItemFields.SyncInfo); syncedItem.Item = _dtoService().GetBaseItemDto(libraryItem, dtoOptions); // TODO: this should be the media source of the transcoded output syncedItem.Item.MediaSources = syncedItem.Item.MediaSources .Where(i => string.Equals(i.Id, jobItem.MediaSourceId)) .ToList(); var mediaSource = syncedItem.Item.MediaSources .FirstOrDefault(i => string.Equals(i.Id, jobItem.MediaSourceId)); // This will be null for items that are not audio/video if (mediaSource == null) { syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); } else { syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); } return(syncedItem); }
private SyncJobItem GetJobItem(IDataReader reader) { var info = new SyncJobItem { Id = reader.GetGuid(0).ToString("N"), ItemId = reader.GetString(1) }; if (!reader.IsDBNull(2)) { info.ItemName = reader.GetString(2); } if (!reader.IsDBNull(3)) { info.MediaSourceId = reader.GetString(3); } info.JobId = reader.GetString(4); info.RequiresConversion = reader.GetBoolean(5); if (!reader.IsDBNull(6)) { info.OutputPath = reader.GetString(6); } if (!reader.IsDBNull(7)) { info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(7), true); } info.TargetId = reader.GetString(8); info.DateCreated = reader.GetDateTime(9); if (!reader.IsDBNull(10)) { info.Progress = reader.GetDouble(10); } return(info); }
private async Task ConvertSubtitles(SyncJobItem jobItem, IEnumerable <SubtitleStreamInfo> subtitles, StreamInfo streamInfo, CancellationToken cancellationToken) { var files = new List <ItemFileInfo>(); var mediaStreams = jobItem.MediaSource.MediaStreams .Where(i => i.Type != MediaStreamType.Subtitle || !i.IsExternal) .ToList(); var startingIndex = mediaStreams.Count == 0 ? 0 : (mediaStreams.Select(i => i.Index).Max() + 1); foreach (var subtitle in subtitles) { var fileInfo = await ConvertSubtitles(jobItem.TemporaryPath, streamInfo, subtitle, cancellationToken).ConfigureAwait(false); // Reset this to a value that will be based on the output media fileInfo.Index = startingIndex; files.Add(fileInfo); mediaStreams.Add(new MediaStream { Index = startingIndex, Codec = subtitle.Format, IsForced = subtitle.IsForced, IsExternal = true, Language = subtitle.Language, Path = fileInfo.Path, SupportsExternalStream = true, Type = MediaStreamType.Subtitle }); startingIndex++; } jobItem.AdditionalFiles.AddRange(files); jobItem.MediaSource.MediaStreams = mediaStreams; }
private SyncJobItem GetSyncJobItem(IDataReader reader) { var info = new SyncJobItem { Id = reader.GetGuid(0).ToString("N"), ItemId = reader.GetString(1), JobId = reader.GetString(2) }; if (!reader.IsDBNull(3)) { info.OutputPath = reader.GetString(3); } if (!reader.IsDBNull(4)) { info.Status = (SyncJobStatus)Enum.Parse(typeof(SyncJobStatus), reader.GetString(4), true); } info.TargetId = reader.GetString(5); return(info); }
public VideoOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job) { var profile = GetDeviceProfile(jobItem.TargetId); var maxBitrate = profile.MaxStaticBitrate; if (maxBitrate.HasValue) { if (job.Quality == SyncQuality.Medium) { maxBitrate = Convert.ToInt32(maxBitrate.Value * .75); } else if (job.Quality == SyncQuality.Low) { maxBitrate = Convert.ToInt32(maxBitrate.Value * .5); } } return(new VideoOptions { Profile = profile, MaxBitrate = maxBitrate }); }
private void FillMetadata(SyncJobItem jobItem) { var item = _libraryManager.GetItemById(jobItem.ItemId); if (item == null) { return; } var primaryImage = item.GetImageInfo(ImageType.Primary, 0); var itemWithImage = item; if (primaryImage == null) { var parentWithImage = item.GetParents().FirstOrDefault(i => i.HasImage(ImageType.Primary)); if (parentWithImage != null) { itemWithImage = parentWithImage; primaryImage = parentWithImage.GetImageInfo(ImageType.Primary, 0); } } if (primaryImage != null) { try { jobItem.PrimaryImageTag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Primary); jobItem.PrimaryImageItemId = itemWithImage.Id.ToString("N"); } catch (Exception ex) { _logger.ErrorException("Error getting image info", ex); } } }
public string GetTemporaryPath(SyncJobItem jobItem) { return(Path.Combine(GetTemporaryPath(jobItem.JobId), jobItem.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 <string> DownloadFile(SyncJobItem jobItem, MediaSourceInfo mediaSource, CancellationToken cancellationToken) { // TODO: Download return(mediaSource.Path); }
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 = _syncManager.GetJobItems(new SyncJobItemQuery { JobId = job.Id, AddMetadata = false }).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; } var index = jobItems.Count == 0 ? 0 : (jobItems.Select(i => i.JobItemIndex).Max() + 1); jobItem = new SyncJobItem { Id = Guid.NewGuid().ToString("N"), ItemId = itemId, ItemName = GetSyncJobItemName(item), JobId = job.Id, TargetId = job.TargetId, DateCreated = DateTime.UtcNow, JobItemIndex = index }; await _syncRepo.Create(jobItem).ConfigureAwait(false); _syncManager.OnSyncJobItemCreated(jobItem); jobItems.Add(jobItem); } jobItems = jobItems .OrderBy(i => i.DateCreated) .ToList(); await UpdateJobStatus(job, jobItems).ConfigureAwait(false); }
public async Task Update(SyncJobItem jobItem) { if (jobItem == null) { throw new ArgumentNullException("jobItem"); } await _writeLock.WaitAsync().ConfigureAwait(false); IDbTransaction transaction = null; try { transaction = _connection.BeginTransaction(); var index = 0; _saveJobItemCommand.GetParameter(index++).Value = new Guid(jobItem.Id); _saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemName; _saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSourceId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.JobId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.RequiresConversion; _saveJobItemCommand.GetParameter(index++).Value = jobItem.OutputPath; _saveJobItemCommand.GetParameter(index++).Value = jobItem.Status.ToString(); _saveJobItemCommand.GetParameter(index++).Value = jobItem.TargetId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.DateCreated; _saveJobItemCommand.GetParameter(index++).Value = jobItem.Progress; _saveJobItemCommand.Transaction = transaction; _saveJobItemCommand.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 SyncJobItem GetJobItem(IDataReader reader) { var info = new SyncJobItem { Id = reader.GetGuid(0).ToString("N"), ItemId = reader.GetString(1) }; if (!reader.IsDBNull(2)) { info.ItemName = reader.GetString(2); } if (!reader.IsDBNull(3)) { info.MediaSourceId = reader.GetString(3); } info.JobId = reader.GetString(4); if (!reader.IsDBNull(5)) { info.TemporaryPath = reader.GetString(5); } if (!reader.IsDBNull(6)) { info.OutputPath = reader.GetString(6); } if (!reader.IsDBNull(7)) { info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(7), true); } info.TargetId = reader.GetString(8); info.DateCreated = reader.GetDateTime(9).ToUniversalTime(); if (!reader.IsDBNull(10)) { info.Progress = reader.GetDouble(10); } if (!reader.IsDBNull(11)) { var json = reader.GetString(11); if (!string.IsNullOrWhiteSpace(json)) { info.AdditionalFiles = _json.DeserializeFromString <List <ItemFileInfo> >(json); } } if (!reader.IsDBNull(12)) { var json = reader.GetString(12); if (!string.IsNullOrWhiteSpace(json)) { info.MediaSource = _json.DeserializeFromString <MediaSourceInfo>(json); } } info.IsMarkedForRemoval = reader.GetBoolean(13); info.JobItemIndex = reader.GetInt32(14); return(info); }
public Task Create(SyncJobItem jobItem) { return(Update(jobItem)); }
public Task Update(SyncJobItem jobItem) { return(InsertOrUpdate(jobItem, _updateJobItemCommand)); }
public bool AllowDuplicateJobItem(SyncJobItem original, SyncJobItem duplicate) { return(false); }
public Task Create(SyncJobItem jobItem) { return(InsertOrUpdate(jobItem, true)); }
private async Task InsertOrUpdate(SyncJobItem jobItem, bool insert) { if (jobItem == null) { throw new ArgumentNullException("jobItem"); } CheckDisposed(); using (var connection = await CreateConnection().ConfigureAwait(false)) { using (var cmd = connection.CreateCommand()) { if (insert) { cmd.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)"; cmd.Parameters.Add(cmd, "@Id"); cmd.Parameters.Add(cmd, "@ItemId"); cmd.Parameters.Add(cmd, "@ItemName"); cmd.Parameters.Add(cmd, "@MediaSourceId"); cmd.Parameters.Add(cmd, "@JobId"); cmd.Parameters.Add(cmd, "@TemporaryPath"); cmd.Parameters.Add(cmd, "@OutputPath"); cmd.Parameters.Add(cmd, "@Status"); cmd.Parameters.Add(cmd, "@TargetId"); cmd.Parameters.Add(cmd, "@DateCreated"); cmd.Parameters.Add(cmd, "@Progress"); cmd.Parameters.Add(cmd, "@AdditionalFiles"); cmd.Parameters.Add(cmd, "@MediaSource"); cmd.Parameters.Add(cmd, "@IsMarkedForRemoval"); cmd.Parameters.Add(cmd, "@JobItemIndex"); cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks"); } else { // cmd cmd.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id"; cmd.Parameters.Add(cmd, "@Id"); cmd.Parameters.Add(cmd, "@ItemId"); cmd.Parameters.Add(cmd, "@ItemName"); cmd.Parameters.Add(cmd, "@MediaSourceId"); cmd.Parameters.Add(cmd, "@JobId"); cmd.Parameters.Add(cmd, "@TemporaryPath"); cmd.Parameters.Add(cmd, "@OutputPath"); cmd.Parameters.Add(cmd, "@Status"); cmd.Parameters.Add(cmd, "@TargetId"); cmd.Parameters.Add(cmd, "@DateCreated"); cmd.Parameters.Add(cmd, "@Progress"); cmd.Parameters.Add(cmd, "@AdditionalFiles"); cmd.Parameters.Add(cmd, "@MediaSource"); cmd.Parameters.Add(cmd, "@IsMarkedForRemoval"); cmd.Parameters.Add(cmd, "@JobItemIndex"); cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks"); } IDbTransaction transaction = null; try { transaction = connection.BeginTransaction(); var index = 0; cmd.GetParameter(index++).Value = new Guid(jobItem.Id); cmd.GetParameter(index++).Value = jobItem.ItemId; cmd.GetParameter(index++).Value = jobItem.ItemName; cmd.GetParameter(index++).Value = jobItem.MediaSourceId; cmd.GetParameter(index++).Value = jobItem.JobId; cmd.GetParameter(index++).Value = jobItem.TemporaryPath; cmd.GetParameter(index++).Value = jobItem.OutputPath; cmd.GetParameter(index++).Value = jobItem.Status.ToString(); cmd.GetParameter(index++).Value = jobItem.TargetId; cmd.GetParameter(index++).Value = jobItem.DateCreated; cmd.GetParameter(index++).Value = jobItem.Progress; cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles); cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource); cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval; cmd.GetParameter(index++).Value = jobItem.JobItemIndex; cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks; cmd.Transaction = transaction; cmd.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(); } } } } }
public Task Update(SyncJobItem jobItem) { return(InsertOrUpdate(jobItem, false)); }
public Task Create(SyncJobItem jobItem) { return(InsertOrUpdate(jobItem, _insertJobItemCommand)); }
private async Task Sync(SyncJobItem jobItem, Audio item, User user, DeviceProfile profile, IProgress <double> progress, CancellationToken cancellationToken) { var options = new AudioOptions { Context = EncodingContext.Static, ItemId = item.Id.ToString("N"), DeviceId = jobItem.TargetId, Profile = profile, MediaSources = item.GetMediaSources(false, user).ToList() }; var streamInfo = new StreamBuilder().BuildAudioItem(options); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; if (streamInfo.PlayMethod == PlayMethod.Transcode) { jobItem.Status = SyncJobItemStatus.Converting; jobItem.RequiresConversion = true; await _syncRepo.Update(jobItem).ConfigureAwait(false); try { jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile), progress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncRepo.Update(jobItem).ConfigureAwait(false); return; } } else { jobItem.RequiresConversion = false; 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.Progress = 50; jobItem.Status = SyncJobItemStatus.Transferring; await _syncRepo.Update(jobItem).ConfigureAwait(false); }
private async Task InsertOrUpdate(SyncJobItem jobItem, IDbCommand cmd) { if (jobItem == null) { throw new ArgumentNullException("jobItem"); } CheckDisposed(); await WriteLock.WaitAsync().ConfigureAwait(false); IDbTransaction transaction = null; try { transaction = _connection.BeginTransaction(); var index = 0; cmd.GetParameter(index++).Value = new Guid(jobItem.Id); cmd.GetParameter(index++).Value = jobItem.ItemId; cmd.GetParameter(index++).Value = jobItem.ItemName; cmd.GetParameter(index++).Value = jobItem.MediaSourceId; cmd.GetParameter(index++).Value = jobItem.JobId; cmd.GetParameter(index++).Value = jobItem.TemporaryPath; cmd.GetParameter(index++).Value = jobItem.OutputPath; cmd.GetParameter(index++).Value = jobItem.Status.ToString(); cmd.GetParameter(index++).Value = jobItem.TargetId; cmd.GetParameter(index++).Value = jobItem.DateCreated; cmd.GetParameter(index++).Value = jobItem.Progress; cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles); cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource); cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval; cmd.GetParameter(index++).Value = jobItem.JobItemIndex; cmd.Transaction = transaction; cmd.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 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); }
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); } }
private SyncJobItem GetJobItem(IReadOnlyList <IResultSetValue> reader) { var info = new SyncJobItem { Id = reader[0].ReadGuid().ToString("N"), ItemId = reader[1].ToString() }; if (reader[2].SQLiteType != SQLiteType.Null) { info.ItemName = reader[2].ToString(); } if (reader[3].SQLiteType != SQLiteType.Null) { info.MediaSourceId = reader[3].ToString(); } info.JobId = reader[4].ToString(); if (reader[5].SQLiteType != SQLiteType.Null) { info.TemporaryPath = reader[5].ToString(); } if (reader[6].SQLiteType != SQLiteType.Null) { info.OutputPath = reader[6].ToString(); } if (reader[7].SQLiteType != SQLiteType.Null) { info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader[7].ToString(), true); } info.TargetId = reader[8].ToString(); info.DateCreated = reader[9].ReadDateTime(); if (reader[10].SQLiteType != SQLiteType.Null) { info.Progress = reader[10].ToDouble(); } if (reader[11].SQLiteType != SQLiteType.Null) { var json = reader[11].ToString(); if (!string.IsNullOrWhiteSpace(json)) { info.AdditionalFiles = _json.DeserializeFromString <List <ItemFileInfo> >(json); } } if (reader[12].SQLiteType != SQLiteType.Null) { var json = reader[12].ToString(); if (!string.IsNullOrWhiteSpace(json)) { info.MediaSource = _json.DeserializeFromString <MediaSourceInfo>(json); } } info.IsMarkedForRemoval = reader[13].ToBool(); info.JobItemIndex = reader[14].ToInt(); if (reader[15].SQLiteType != SQLiteType.Null) { info.ItemDateModifiedTicks = reader[15].ToInt64(); } return(info); }
private SyncedItem GetJobItemInfo(SyncJobItem jobItem) { var job = _repo.GetJob(jobItem.JobId); if (job == null) { _logger.Error("GetJobItemInfo job id {0} no longer exists", jobItem.JobId); return(null); } var libraryItem = _libraryManager.GetItemById(jobItem.ItemId); if (libraryItem == null) { _logger.Error("GetJobItemInfo library item with id {0} no longer exists", jobItem.ItemId); return(null); } var syncedItem = new SyncedItem { SyncJobId = jobItem.JobId, SyncJobItemId = jobItem.Id, ServerId = _appHost.SystemId, UserId = job.UserId, SyncJobName = job.Name, SyncJobDateCreated = job.DateCreated, AdditionalFiles = jobItem.AdditionalFiles.Select(i => new ItemFileInfo { ImageType = i.ImageType, Name = i.Name, Type = i.Type, Index = i.Index }).ToList() }; var dtoOptions = new DtoOptions(); // Remove some bloat dtoOptions.Fields.Remove(ItemFields.MediaStreams); dtoOptions.Fields.Remove(ItemFields.IndexOptions); dtoOptions.Fields.Remove(ItemFields.MediaSourceCount); dtoOptions.Fields.Remove(ItemFields.Path); dtoOptions.Fields.Remove(ItemFields.SeriesGenres); dtoOptions.Fields.Remove(ItemFields.Settings); dtoOptions.Fields.Remove(ItemFields.SyncInfo); dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo); syncedItem.Item = _dtoService().GetBaseItemDto(libraryItem, dtoOptions); var mediaSource = jobItem.MediaSource; syncedItem.Item.MediaSources = new List <MediaSourceInfo>(); syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); if (string.IsNullOrWhiteSpace(syncedItem.OriginalFileName)) { syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); } // This will be null for items that are not audio/video if (mediaSource != null) { syncedItem.OriginalFileName = Path.ChangeExtension(syncedItem.OriginalFileName, Path.GetExtension(mediaSource.Path)); syncedItem.Item.MediaSources.Add(mediaSource); } if (string.IsNullOrWhiteSpace(syncedItem.OriginalFileName)) { syncedItem.OriginalFileName = libraryItem.Name; } return(syncedItem); }
private bool AllowDuplicateJobItem(IHasDuplicateCheck provider, SyncJobItem original, SyncJobItem duplicate) { if (provider != null) { return(provider.AllowDuplicateJobItem(original, duplicate)); } return(true); }