mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-13 21:56:20 +00:00
sync updates
This commit is contained in:
@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Connect
|
||||
{
|
||||
LoadCachedAddress();
|
||||
|
||||
_timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(10), TimeSpan.FromHours(6));
|
||||
_timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3));
|
||||
}
|
||||
|
||||
private async void TimerCallback(object state)
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MimeTypes = MediaBrowser.Common.Net.MimeTypes;
|
||||
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
|
||||
@@ -30,12 +30,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// This is a bit of a one-off but it's here to combat MCM's over-aggressive placement of collection.xml files where they don't belong, including in series folders.
|
||||
if (args.ContainsMetaFileByName("series.xml"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
args.ContainsFileSystemEntryByName("collection.xml"))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
@@ -23,9 +25,11 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
private readonly ConcurrentDictionary<string, UserItemData> _userData = new ConcurrentDictionary<string, UserItemData>();
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public UserDataManager(ILogManager logManager)
|
||||
public UserDataManager(ILogManager logManager, IServerConfigurationManager config)
|
||||
{
|
||||
_config = config;
|
||||
_logger = logManager.GetLogger(GetType().Name);
|
||||
}
|
||||
|
||||
@@ -35,22 +39,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
/// <value>The repository.</value>
|
||||
public IUserDataRepository Repository { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Saves the user data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="userData">The user data.</param>
|
||||
/// <param name="reason">The reason.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">userData
|
||||
/// or
|
||||
/// cancellationToken
|
||||
/// or
|
||||
/// userId
|
||||
/// or
|
||||
/// key</exception>
|
||||
public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
|
||||
{
|
||||
if (userData == null)
|
||||
@@ -219,5 +207,59 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
Key = data.Key
|
||||
};
|
||||
}
|
||||
|
||||
public bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks)
|
||||
{
|
||||
var playedToCompletion = false;
|
||||
|
||||
var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
|
||||
|
||||
// If a position has been reported, and if we know the duration
|
||||
if (positionTicks > 0 && hasRuntime)
|
||||
{
|
||||
var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
|
||||
|
||||
// Don't track in very beginning
|
||||
if (pctIn < _config.Configuration.MinResumePct)
|
||||
{
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
// If we're at the end, assume completed
|
||||
else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value)
|
||||
{
|
||||
positionTicks = 0;
|
||||
data.Played = playedToCompletion = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Enforce MinResumeDuration
|
||||
var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds;
|
||||
|
||||
if (durationSeconds < _config.Configuration.MinResumeDurationSeconds)
|
||||
{
|
||||
positionTicks = 0;
|
||||
data.Played = playedToCompletion = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!hasRuntime)
|
||||
{
|
||||
// If we don't know the runtime we'll just have to assume it was fully played
|
||||
data.Played = playedToCompletion = true;
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
if (item is Audio)
|
||||
{
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
data.PlaybackPositionTicks = positionTicks;
|
||||
|
||||
return playedToCompletion;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,6 @@
|
||||
"HeaderDeleteItem": "Delete Item",
|
||||
"ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
|
||||
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
|
||||
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
|
||||
"MessageItemSaved": "Item saved.",
|
||||
"OptionEnded": "Ended",
|
||||
"OptionContinuing": "Continuing",
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
"ButtonMoveRight": "Move right",
|
||||
"ButtonBrowseOnlineImages": "Browse online images",
|
||||
"HeaderDeleteItem": "Delete Item",
|
||||
"ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?",
|
||||
"ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
|
||||
"MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
|
||||
"MessageValueNotCorrect": "The value entered is not correct. Please try again.",
|
||||
"MessageItemSaved": "Item saved.",
|
||||
|
||||
@@ -67,12 +67,6 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
private readonly IAuthenticationRepository _authRepo;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration manager.
|
||||
/// </summary>
|
||||
/// <value>The configuration manager.</value>
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _active connections
|
||||
/// </summary>
|
||||
@@ -105,18 +99,9 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
|
||||
private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="userRepository">The user repository.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
|
||||
public SessionManager(IUserDataManager userDataRepository, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager)
|
||||
{
|
||||
_userDataRepository = userDataRepository;
|
||||
_configurationManager = configurationManager;
|
||||
_logger = logger;
|
||||
_userRepository = userRepository;
|
||||
_libraryManager = libraryManager;
|
||||
@@ -689,7 +674,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
|
||||
if (positionTicks.HasValue)
|
||||
{
|
||||
UpdatePlayState(item, data, positionTicks.Value);
|
||||
_userDataRepository.UpdatePlayState(item, data, positionTicks.Value);
|
||||
|
||||
await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
@@ -779,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
|
||||
if (positionTicks.HasValue)
|
||||
{
|
||||
playedToCompletion = UpdatePlayState(item, data, positionTicks.Value);
|
||||
playedToCompletion = _userDataRepository.UpdatePlayState(item, data, positionTicks.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -795,65 +780,6 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
return playedToCompletion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates playstate position for an item but does not save
|
||||
/// </summary>
|
||||
/// <param name="item">The item</param>
|
||||
/// <param name="data">User data for the item</param>
|
||||
/// <param name="positionTicks">The current playback position</param>
|
||||
private bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks)
|
||||
{
|
||||
var playedToCompletion = false;
|
||||
|
||||
var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0;
|
||||
|
||||
// If a position has been reported, and if we know the duration
|
||||
if (positionTicks > 0 && hasRuntime)
|
||||
{
|
||||
var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100;
|
||||
|
||||
// Don't track in very beginning
|
||||
if (pctIn < _configurationManager.Configuration.MinResumePct)
|
||||
{
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
// If we're at the end, assume completed
|
||||
else if (pctIn > _configurationManager.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value)
|
||||
{
|
||||
positionTicks = 0;
|
||||
data.Played = playedToCompletion = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Enforce MinResumeDuration
|
||||
var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds;
|
||||
|
||||
if (durationSeconds < _configurationManager.Configuration.MinResumeDurationSeconds)
|
||||
{
|
||||
positionTicks = 0;
|
||||
data.Played = playedToCompletion = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!hasRuntime)
|
||||
{
|
||||
// If we don't know the runtime we'll just have to assume it was fully played
|
||||
data.Played = playedToCompletion = true;
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
if (item is Audio)
|
||||
{
|
||||
positionTicks = 0;
|
||||
}
|
||||
|
||||
data.PlaybackPositionTicks = positionTicks;
|
||||
|
||||
return playedToCompletion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the session.
|
||||
/// </summary>
|
||||
|
||||
@@ -358,6 +358,9 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
var streamInfo = new StreamBuilder().BuildVideoItem(options);
|
||||
var mediaSource = streamInfo.MediaSource;
|
||||
|
||||
jobItem.MediaSourceId = streamInfo.MediaSourceId;
|
||||
await _syncRepo.Update(jobItem).ConfigureAwait(false);
|
||||
|
||||
if (streamInfo.PlayMethod != PlayMethod.Transcode)
|
||||
{
|
||||
if (mediaSource.Protocol == MediaProtocol.File)
|
||||
@@ -389,6 +392,9 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
var streamInfo = new StreamBuilder().BuildAudioItem(options);
|
||||
var mediaSource = streamInfo.MediaSource;
|
||||
|
||||
jobItem.MediaSourceId = streamInfo.MediaSourceId;
|
||||
await _syncRepo.Update(jobItem).ConfigureAwait(false);
|
||||
|
||||
if (streamInfo.PlayMethod != PlayMethod.Transcode)
|
||||
{
|
||||
if (mediaSource.Protocol == MediaProtocol.File)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@@ -7,10 +11,12 @@ using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Sync;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Sync;
|
||||
using MediaBrowser.Model.Users;
|
||||
using MoreLinq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -26,16 +32,20 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
private ISyncProvider[] _providers = { };
|
||||
|
||||
public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager)
|
||||
public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, IDtoService dtoService, IApplicationHost appHost)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_repo = repo;
|
||||
_imageProcessor = imageProcessor;
|
||||
_logger = logger;
|
||||
_userManager = userManager;
|
||||
_dtoService = dtoService;
|
||||
_appHost = appHost;
|
||||
}
|
||||
|
||||
public void AddParts(IEnumerable<ISyncProvider> providers)
|
||||
@@ -251,6 +261,11 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
}
|
||||
}
|
||||
|
||||
if (item is LiveTvChannel || item is IChannelItem || item is ILiveTvRecording)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -301,5 +316,54 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
{
|
||||
return _repo.GetJobItems(query);
|
||||
}
|
||||
|
||||
public SyncedItem GetJobItemInfo(string id)
|
||||
{
|
||||
var jobItem = GetJobItem(id);
|
||||
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
|
||||
};
|
||||
|
||||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
|
||||
|
||||
syncedItem.Item = _dtoService.GetBaseItemDto(libraryItem, new DtoOptions
|
||||
{
|
||||
Fields = fields
|
||||
});
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
public Task ReportOfflineAction(UserAction action)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
var dbFile = Path.Combine(_appPaths.DataPath, "sync6.db");
|
||||
var dbFile = Path.Combine(_appPaths.DataPath, "sync7.db");
|
||||
|
||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
"create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Quality TEXT NOT NULL, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
|
||||
"create index if not exists idx_SyncJobs on SyncJobs(Id)",
|
||||
|
||||
"create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)",
|
||||
"create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, MediaSourceId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)",
|
||||
"create index if not exists idx_SyncJobItems on SyncJobs(Id)",
|
||||
|
||||
//pragmas
|
||||
@@ -90,10 +90,11 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
_saveJobCommand.Parameters.Add(_saveJobCommand, "@ItemCount");
|
||||
|
||||
_saveJobItemCommand = _connection.CreateCommand();
|
||||
_saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)";
|
||||
_saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @MediaSourceId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)";
|
||||
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Id");
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@ItemId");
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@MediaSourceId");
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@JobId");
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@OutputPath");
|
||||
_saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Status");
|
||||
@@ -103,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
}
|
||||
|
||||
private const string BaseJobSelectText = "select Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
|
||||
private const string BaseJobItemSelectText = "select Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems";
|
||||
private const string BaseJobItemSelectText = "select Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems";
|
||||
|
||||
public SyncJob GetJob(string id)
|
||||
{
|
||||
@@ -556,6 +557,7 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
|
||||
_saveJobItemCommand.GetParameter(index++).Value = new Guid(jobItem.Id);
|
||||
_saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemId;
|
||||
_saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSourceId;
|
||||
_saveJobItemCommand.GetParameter(index++).Value = jobItem.JobId;
|
||||
_saveJobItemCommand.GetParameter(index++).Value = jobItem.OutputPath;
|
||||
_saveJobItemCommand.GetParameter(index++).Value = jobItem.Status;
|
||||
@@ -606,26 +608,27 @@ namespace MediaBrowser.Server.Implementations.Sync
|
||||
{
|
||||
Id = reader.GetGuid(0).ToString("N"),
|
||||
ItemId = reader.GetString(1),
|
||||
JobId = reader.GetString(2)
|
||||
MediaSourceId = reader.GetString(2),
|
||||
JobId = reader.GetString(3)
|
||||
};
|
||||
|
||||
if (!reader.IsDBNull(3))
|
||||
{
|
||||
info.OutputPath = reader.GetString(3);
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(4))
|
||||
{
|
||||
info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(4), true);
|
||||
info.OutputPath = reader.GetString(4);
|
||||
}
|
||||
|
||||
info.TargetId = reader.GetString(5);
|
||||
|
||||
info.DateCreated = reader.GetDateTime(6);
|
||||
|
||||
if (!reader.IsDBNull(7))
|
||||
if (!reader.IsDBNull(5))
|
||||
{
|
||||
info.Progress = reader.GetDouble(7);
|
||||
info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(5), true);
|
||||
}
|
||||
|
||||
info.TargetId = reader.GetString(6);
|
||||
|
||||
info.DateCreated = reader.GetDateTime(7);
|
||||
|
||||
if (!reader.IsDBNull(8))
|
||||
{
|
||||
info.Progress = reader.GetDouble(8);
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
Reference in New Issue
Block a user