commit
b09e0a6e29
|
@ -736,7 +736,8 @@ namespace Emby.Drawing
|
||||||
{
|
{
|
||||||
var filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N");
|
var filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N");
|
||||||
|
|
||||||
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + ".webp");
|
var cacheExtension = _mediaEncoder().SupportsEncoder("libwebp") ? ".webp" : ".png";
|
||||||
|
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
|
||||||
|
|
||||||
var file = _fileSystem.GetFileInfo(outputPath);
|
var file = _fileSystem.GetFileInfo(outputPath);
|
||||||
if (!file.Exists)
|
if (!file.Exists)
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.Collections
|
||||||
return subItem;
|
return subItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = subItem.GetParent();
|
var parent = subItem.IsOwnedItem ? subItem.GetOwner() : subItem.GetParent();
|
||||||
|
|
||||||
if (parent != null && parent.HasImage(ImageType.Primary))
|
if (parent != null && parent.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
|
|
|
@ -253,6 +253,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
AddColumn(db, "TypedBaseItems", "ExternalId", "Text", existingColumnNames);
|
AddColumn(db, "TypedBaseItems", "ExternalId", "Text", existingColumnNames);
|
||||||
AddColumn(db, "TypedBaseItems", "SeriesPresentationUniqueKey", "Text", existingColumnNames);
|
AddColumn(db, "TypedBaseItems", "SeriesPresentationUniqueKey", "Text", existingColumnNames);
|
||||||
AddColumn(db, "TypedBaseItems", "ShowId", "Text", existingColumnNames);
|
AddColumn(db, "TypedBaseItems", "ShowId", "Text", existingColumnNames);
|
||||||
|
AddColumn(db, "TypedBaseItems", "OwnerId", "Text", existingColumnNames);
|
||||||
|
|
||||||
existingColumnNames = GetColumnNames(db, "ItemValues");
|
existingColumnNames = GetColumnNames(db, "ItemValues");
|
||||||
AddColumn(db, "ItemValues", "CleanValue", "Text", existingColumnNames);
|
AddColumn(db, "ItemValues", "CleanValue", "Text", existingColumnNames);
|
||||||
|
@ -459,7 +460,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
"AlbumArtists",
|
"AlbumArtists",
|
||||||
"ExternalId",
|
"ExternalId",
|
||||||
"SeriesPresentationUniqueKey",
|
"SeriesPresentationUniqueKey",
|
||||||
"ShowId"
|
"ShowId",
|
||||||
|
"OwnerId"
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly string[] _mediaStreamSaveColumns =
|
private readonly string[] _mediaStreamSaveColumns =
|
||||||
|
@ -580,7 +582,8 @@ namespace Emby.Server.Implementations.Data
|
||||||
"AlbumArtists",
|
"AlbumArtists",
|
||||||
"ExternalId",
|
"ExternalId",
|
||||||
"SeriesPresentationUniqueKey",
|
"SeriesPresentationUniqueKey",
|
||||||
"ShowId"
|
"ShowId",
|
||||||
|
"OwnerId"
|
||||||
};
|
};
|
||||||
|
|
||||||
var saveItemCommandCommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
|
var saveItemCommandCommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
|
||||||
|
@ -784,13 +787,14 @@ namespace Emby.Server.Implementations.Data
|
||||||
saveItemStatement.TryBind("@PremiereDate", item.PremiereDate);
|
saveItemStatement.TryBind("@PremiereDate", item.PremiereDate);
|
||||||
saveItemStatement.TryBind("@ProductionYear", item.ProductionYear);
|
saveItemStatement.TryBind("@ProductionYear", item.ProductionYear);
|
||||||
|
|
||||||
if (item.ParentId == Guid.Empty)
|
var parentId = item.ParentId;
|
||||||
|
if (parentId == Guid.Empty)
|
||||||
{
|
{
|
||||||
saveItemStatement.TryBindNull("@ParentId");
|
saveItemStatement.TryBindNull("@ParentId");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
saveItemStatement.TryBind("@ParentId", item.ParentId);
|
saveItemStatement.TryBind("@ParentId", parentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Genres.Count > 0)
|
if (item.Genres.Count > 0)
|
||||||
|
@ -1057,6 +1061,16 @@ namespace Emby.Server.Implementations.Data
|
||||||
saveItemStatement.TryBindNull("@ShowId");
|
saveItemStatement.TryBindNull("@ShowId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ownerId = item.OwnerId;
|
||||||
|
if (ownerId != Guid.Empty)
|
||||||
|
{
|
||||||
|
saveItemStatement.TryBind("@OwnerId", ownerId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
saveItemStatement.TryBindNull("@OwnerId");
|
||||||
|
}
|
||||||
|
|
||||||
saveItemStatement.MoveNext();
|
saveItemStatement.MoveNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,16 +1170,14 @@ namespace Emby.Server.Implementations.Data
|
||||||
delimeter +
|
delimeter +
|
||||||
image.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) +
|
image.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) +
|
||||||
delimeter +
|
delimeter +
|
||||||
image.Type +
|
image.Type;
|
||||||
delimeter +
|
|
||||||
image.IsPlaceholder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemImageInfo ItemImageInfoFromValueString(string value)
|
public ItemImageInfo ItemImageInfoFromValueString(string value)
|
||||||
{
|
{
|
||||||
var parts = value.Split(new[] { '*' }, StringSplitOptions.None);
|
var parts = value.Split(new[] { '*' }, StringSplitOptions.None);
|
||||||
|
|
||||||
if (parts.Length != 4)
|
if (parts.Length < 3)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1173,9 +1185,18 @@ namespace Emby.Server.Implementations.Data
|
||||||
var image = new ItemImageInfo();
|
var image = new ItemImageInfo();
|
||||||
|
|
||||||
image.Path = parts[0];
|
image.Path = parts[0];
|
||||||
image.DateModified = new DateTime(long.Parse(parts[1], CultureInfo.InvariantCulture), DateTimeKind.Utc);
|
|
||||||
image.Type = (ImageType)Enum.Parse(typeof(ImageType), parts[2], true);
|
long ticks;
|
||||||
image.IsPlaceholder = string.Equals(parts[3], true.ToString(), StringComparison.OrdinalIgnoreCase);
|
if (long.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
|
||||||
|
{
|
||||||
|
image.DateModified = new DateTime(ticks, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageType type;
|
||||||
|
if (Enum.TryParse(parts[2], true, out type))
|
||||||
|
{
|
||||||
|
image.Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -1965,6 +1986,12 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!reader.IsDBNull(index))
|
||||||
|
{
|
||||||
|
item.OwnerId = reader.GetGuid(index);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4467,7 +4494,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var includedItemByNameTypes = GetItemByNameTypesInQuery(query).SelectMany(MapIncludeItemTypes).ToList();
|
var includedItemByNameTypes = GetItemByNameTypesInQuery(query).SelectMany(MapIncludeItemTypes).ToList();
|
||||||
var enableItemsByName = (query.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
|
var enableItemsByName = (query.IncludeItemsByName ?? false) && includedItemByNameTypes.Count > 0;
|
||||||
|
|
||||||
|
|
|
@ -1487,7 +1487,7 @@ namespace Emby.Server.Implementations.Dto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = currentItem.DisplayParent ?? currentItem.GetParent();
|
var parent = currentItem.DisplayParent ?? (currentItem.IsOwnedItem ? currentItem.GetOwner() : currentItem.GetParent());
|
||||||
|
|
||||||
if (parent == null && !(originalItem is UserRootFolder) && !(originalItem is UserView) && !(originalItem is AggregateFolder) && !(originalItem is ICollectionFolder) && !(originalItem is Channel))
|
if (parent == null && !(originalItem is UserRootFolder) && !(originalItem is UserView) && !(originalItem is AggregateFolder) && !(originalItem is ICollectionFolder) && !(originalItem is Channel))
|
||||||
{
|
{
|
||||||
|
|
|
@ -198,9 +198,10 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||||
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.Item.Parent != null)
|
var parent = e.Item.GetParent() as Folder;
|
||||||
|
if (parent != null)
|
||||||
{
|
{
|
||||||
_foldersAddedTo.Add(e.Item.Parent);
|
_foldersAddedTo.Add(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_itemsAdded.Add(e.Item);
|
_itemsAdded.Add(e.Item);
|
||||||
|
@ -259,9 +260,10 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||||
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.Item.Parent != null)
|
var parent = e.Item.GetParent() as Folder;
|
||||||
|
if (parent != null)
|
||||||
{
|
{
|
||||||
_foldersRemovedFrom.Add(e.Item.Parent);
|
_foldersRemovedFrom.Add(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_itemsRemoved.Add(e.Item);
|
_itemsRemoved.Add(e.Item);
|
||||||
|
|
|
@ -1,43 +1,74 @@
|
||||||
using System;
|
using System;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Plugins;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using MediaBrowser.Model.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.EntryPoints
|
namespace Emby.Server.Implementations.EntryPoints
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class RefreshUsersMetadata
|
/// Class RefreshUsersMetadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RefreshUsersMetadata : IServerEntryPoint
|
public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _user manager
|
/// The _user manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
|
private IFileSystem _fileSystem;
|
||||||
|
|
||||||
|
public string Name => "Refresh Users";
|
||||||
|
|
||||||
|
public string Key => "RefreshUsers";
|
||||||
|
|
||||||
|
public string Description => "Refresh user infos";
|
||||||
|
|
||||||
|
public string Category
|
||||||
|
{
|
||||||
|
get { return "Library"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHidden => true;
|
||||||
|
|
||||||
|
public bool IsEnabled => true;
|
||||||
|
|
||||||
|
public bool IsLogged => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
|
/// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userManager">The user manager.</param>
|
public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem)
|
||||||
public RefreshUsersMetadata(IUserManager userManager)
|
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||||
/// Runs this instance.
|
|
||||||
/// </summary>
|
|
||||||
public async void Run()
|
|
||||||
{
|
{
|
||||||
await _userManager.RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false);
|
var users = _userManager.Users.ToList();
|
||||||
|
|
||||||
|
foreach (var user in users)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
return new List<TaskTriggerInfo>
|
||||||
|
{
|
||||||
|
new TaskTriggerInfo
|
||||||
|
{
|
||||||
|
IntervalTicks = TimeSpan.FromDays(1).Ticks,
|
||||||
|
Type = TaskTriggerInfo.TriggerInterval
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||||
// Go up one level for indicators
|
// Go up one level for indicators
|
||||||
if (baseItem != null)
|
if (baseItem != null)
|
||||||
{
|
{
|
||||||
var parent = baseItem.GetParent();
|
var parent = baseItem.IsOwnedItem ? baseItem.GetOwner() : baseItem.GetParent();
|
||||||
|
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -209,7 +209,7 @@ namespace Emby.Server.Implementations.IO
|
||||||
// If the item has been deleted find the first valid parent that still exists
|
// If the item has been deleted find the first valid parent that still exists
|
||||||
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
|
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
|
||||||
{
|
{
|
||||||
item = item.GetParent();
|
item = item.IsOwnedItem ? item.GetOwner() : item.GetParent();
|
||||||
|
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -386,7 +386,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
item.Id);
|
item.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = item.Parent;
|
var parent = item.IsOwnedItem ? item.GetOwner() : item.GetParent();
|
||||||
|
|
||||||
var locationType = item.LocationType;
|
var locationType = item.LocationType;
|
||||||
|
|
||||||
|
@ -453,12 +453,28 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
await parent.ValidateChildren(new SimpleProgress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false);
|
var parentFolder = parent as Folder;
|
||||||
|
if (parentFolder != null)
|
||||||
|
{
|
||||||
|
await parentFolder.ValidateChildren(new SimpleProgress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await parent.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), CancellationToken.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parent != null)
|
else if (parent != null)
|
||||||
{
|
{
|
||||||
parent.RemoveChild(item);
|
var parentFolder = parent as Folder;
|
||||||
|
if (parentFolder != null)
|
||||||
|
{
|
||||||
|
parentFolder.RemoveChild(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await parent.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), CancellationToken.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemRepository.DeleteItem(item.Id, CancellationToken.None);
|
ItemRepository.DeleteItem(item.Id, CancellationToken.None);
|
||||||
|
@ -2604,8 +2620,11 @@ namespace Emby.Server.Implementations.Library
|
||||||
{
|
{
|
||||||
video = dbItem;
|
video = dbItem;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// item is new
|
||||||
video.ExtraType = ExtraType.Trailer;
|
video.ExtraType = ExtraType.Trailer;
|
||||||
|
}
|
||||||
video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
|
video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
|
||||||
|
|
||||||
return video;
|
return video;
|
||||||
|
@ -2846,13 +2865,6 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
|
await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
var newImage = item.GetImageInfo(image.Type, imageIndex);
|
|
||||||
|
|
||||||
if (newImage != null)
|
|
||||||
{
|
|
||||||
newImage.IsPlaceholder = image.IsPlaceholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
|
await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
return item.GetImageInfo(image.Type, imageIndex);
|
return item.GetImageInfo(image.Type, imageIndex);
|
||||||
|
|
|
@ -518,11 +518,12 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task RefreshUsersMetadata(CancellationToken cancellationToken)
|
public async Task RefreshUsersMetadata(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken)).ToList();
|
foreach (var user in Users)
|
||||||
|
{
|
||||||
return Task.WhenAll(tasks);
|
await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile));
|
||||||
|
|
||||||
using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||||
{
|
{
|
||||||
onStarted();
|
onStarted();
|
||||||
|
@ -76,6 +78,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
_logger.Info("Opened recording stream from tuner provider");
|
_logger.Info("Opened recording stream from tuner provider");
|
||||||
|
|
||||||
|
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile));
|
||||||
|
|
||||||
using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||||
{
|
{
|
||||||
onStarted();
|
onStarted();
|
||||||
|
|
|
@ -1429,14 +1429,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
string liveStreamId = null;
|
string liveStreamId = null;
|
||||||
|
|
||||||
OnRecordingStatusChanged();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var recorder = await GetRecorder().ConfigureAwait(false);
|
var recorder = await GetRecorder().ConfigureAwait(false);
|
||||||
|
|
||||||
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
|
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
_logger.Info("Opening recording stream from tuner provider");
|
||||||
var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
|
var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -1450,23 +1449,20 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
recordPath = EnsureFileUnique(recordPath, timer.Id);
|
recordPath = EnsureFileUnique(recordPath, timer.Id);
|
||||||
|
|
||||||
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
|
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
|
||||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath));
|
|
||||||
activeRecordingInfo.Path = recordPath;
|
activeRecordingInfo.Path = recordPath;
|
||||||
|
|
||||||
var duration = recordingEndDate - DateTime.UtcNow;
|
var duration = recordingEndDate - DateTime.UtcNow;
|
||||||
|
|
||||||
_logger.Info("Beginning recording. Will record for {0} minutes.",
|
_logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
||||||
duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
|
||||||
|
|
||||||
_logger.Info("Writing file to path: " + recordPath);
|
_logger.Info("Writing file to path: " + recordPath);
|
||||||
_logger.Info("Opening recording stream from tuner provider");
|
|
||||||
|
|
||||||
Action onStarted = () =>
|
Action onStarted = async () =>
|
||||||
{
|
{
|
||||||
timer.Status = RecordingStatus.InProgress;
|
timer.Status = RecordingStatus.InProgress;
|
||||||
_timerProvider.AddOrUpdate(timer, false);
|
_timerProvider.AddOrUpdate(timer, false);
|
||||||
|
|
||||||
SaveRecordingMetadata(timer, recordPath, seriesPath);
|
await SaveRecordingMetadata(timer, recordPath, seriesPath).ConfigureAwait(false);
|
||||||
TriggerRefresh(recordPath);
|
TriggerRefresh(recordPath);
|
||||||
EnforceKeepUpTo(timer, seriesPath);
|
EnforceKeepUpTo(timer, seriesPath);
|
||||||
};
|
};
|
||||||
|
@ -1500,7 +1496,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
}
|
}
|
||||||
|
|
||||||
TriggerRefresh(recordPath);
|
TriggerRefresh(recordPath);
|
||||||
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
|
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
|
||||||
|
|
||||||
ActiveRecordingInfo removed;
|
ActiveRecordingInfo removed;
|
||||||
_activeRecordings.TryRemove(timer.Id, out removed);
|
_activeRecordings.TryRemove(timer.Id, out removed);
|
||||||
|
@ -1526,17 +1522,29 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
_timerProvider.Delete(timer);
|
_timerProvider.Delete(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnRecordingStatusChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerRefresh(string path)
|
private void TriggerRefresh(string path)
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Triggering refresh on {0}", path);
|
||||||
|
|
||||||
var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path));
|
var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path));
|
||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
item.ChangedExternally();
|
_logger.Debug("Refreshing recording parent {0}", item.Path);
|
||||||
|
|
||||||
|
_providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
|
||||||
|
{
|
||||||
|
ValidateChildren = true,
|
||||||
|
RefreshPaths = new List<string>
|
||||||
|
{
|
||||||
|
path,
|
||||||
|
_fileSystem.GetDirectoryName(path),
|
||||||
|
_fileSystem.GetDirectoryName(_fileSystem.GetDirectoryName(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
}, RefreshPriority.High);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1544,6 +1552,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
BaseItem item = null;
|
BaseItem item = null;
|
||||||
|
|
||||||
|
var parentPath = _fileSystem.GetDirectoryName(path);
|
||||||
|
|
||||||
while (item == null && !string.IsNullOrEmpty(path))
|
while (item == null && !string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
item = _libraryManager.FindByPath(path, null);
|
item = _libraryManager.FindByPath(path, null);
|
||||||
|
@ -1553,14 +1563,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
// If the item has been deleted find the first valid parent that still exists
|
if (item.GetType() == typeof(Folder) && string.Equals(item.Path, parentPath, StringComparison.OrdinalIgnoreCase))
|
||||||
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
|
|
||||||
{
|
{
|
||||||
item = item.GetParent();
|
var parentItem = item.GetParent();
|
||||||
|
if (parentItem != null && !(parentItem is AggregateFolder))
|
||||||
if (item == null)
|
|
||||||
{
|
{
|
||||||
break;
|
item = parentItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1568,14 +1576,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRecordingStatusChanged()
|
|
||||||
{
|
|
||||||
EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
|
|
||||||
{
|
|
||||||
|
|
||||||
}, _logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void EnforceKeepUpTo(TimerInfo timer, string seriesPath)
|
private async void EnforceKeepUpTo(TimerInfo timer, string seriesPath)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(timer.SeriesTimerId))
|
if (string.IsNullOrWhiteSpace(timer.SeriesTimerId))
|
||||||
|
@ -1960,7 +1960,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveRecordingMetadata(TimerInfo timer, string recordingPath, string seriesPath)
|
private async Task SaveRecordingMetadata(TimerInfo timer, string recordingPath, string seriesPath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -843,8 +843,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
item.SetImage(new ItemImageInfo
|
item.SetImage(new ItemImageInfo
|
||||||
{
|
{
|
||||||
Path = info.ImagePath,
|
Path = info.ImagePath,
|
||||||
Type = ImageType.Primary,
|
Type = ImageType.Primary
|
||||||
IsPlaceholder = true
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(info.ImageUrl))
|
else if (!string.IsNullOrWhiteSpace(info.ImageUrl))
|
||||||
|
@ -852,8 +851,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
item.SetImage(new ItemImageInfo
|
item.SetImage(new ItemImageInfo
|
||||||
{
|
{
|
||||||
Path = info.ImageUrl,
|
Path = info.ImageUrl,
|
||||||
Type = ImageType.Primary,
|
Type = ImageType.Primary
|
||||||
IsPlaceholder = true
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
}
|
}
|
||||||
|
|
||||||
_liveStreamTaskCompletionSource.TrySetResult(true);
|
_liveStreamTaskCompletionSource.TrySetResult(true);
|
||||||
//await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
|
await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
return subItem;
|
return subItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parent = subItem.GetParent();
|
var parent = subItem.IsOwnedItem ? subItem.GetOwner() : subItem.GetParent();
|
||||||
|
|
||||||
if (parent != null && parent.HasImage(ImageType.Primary))
|
if (parent != null && parent.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
FileInfo = FileSystem.GetDirectoryInfo(path),
|
FileInfo = FileSystem.GetDirectoryInfo(path),
|
||||||
Path = path,
|
Path = path,
|
||||||
Parent = Parent
|
Parent = GetParent() as Folder
|
||||||
};
|
};
|
||||||
|
|
||||||
// Gather child folder and files
|
// Gather child folder and files
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public string Tagline { get; set; }
|
public string Tagline { get; set; }
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public ItemImageInfo[] ImageInfos { get; set; }
|
public virtual ItemImageInfo[] ImageInfos { get; set; }
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public bool IsVirtualItem { get; set; }
|
public bool IsVirtualItem { get; set; }
|
||||||
|
@ -216,6 +216,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public Guid OwnerId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this instance is hd.
|
/// Gets or sets a value indicating whether this instance is hd.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -321,10 +324,29 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (OwnerId != Guid.Empty)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// legacy
|
||||||
|
|
||||||
// Local trailer, special feature, theme video, etc.
|
// Local trailer, special feature, theme video, etc.
|
||||||
// An item that belongs to another item but is not part of the Parent-Child tree
|
// An item that belongs to another item but is not part of the Parent-Child tree
|
||||||
return !IsFolder && ParentId == Guid.Empty && LocationType == LocationType.FileSystem;
|
// This is a hack for now relying on ExtraType. Eventually we may need to persist this
|
||||||
|
if (ParentId == Guid.Empty && !IsFolder && LocationType == LocationType.FileSystem)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseItem GetOwner()
|
||||||
|
{
|
||||||
|
var ownerId = OwnerId;
|
||||||
|
return ownerId == Guid.Empty ? null : LibraryManager.GetItemById(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -727,17 +749,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
ParentId = parent == null ? Guid.Empty : parent.Id;
|
ParentId = parent == null ? Guid.Empty : parent.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public IEnumerable<Folder> Parents
|
|
||||||
{
|
|
||||||
get { return GetParents().OfType<Folder>(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseItem GetParent()
|
public BaseItem GetParent()
|
||||||
{
|
{
|
||||||
if (ParentId != Guid.Empty)
|
var parentId = ParentId;
|
||||||
|
if (parentId != Guid.Empty)
|
||||||
{
|
{
|
||||||
return LibraryManager.GetItemById(ParentId);
|
return LibraryManager.GetItemById(parentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -779,11 +796,13 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (ParentId == Guid.Empty)
|
var parentId = ParentId;
|
||||||
|
|
||||||
|
if (parentId == Guid.Empty)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return ParentId;
|
return parentId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,8 +1021,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
audio = dbItem;
|
audio = dbItem;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// item is new
|
||||||
audio.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeSong;
|
audio.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeSong;
|
||||||
|
}
|
||||||
|
|
||||||
return audio;
|
return audio;
|
||||||
|
|
||||||
|
@ -1032,8 +1054,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
item = dbItem;
|
item = dbItem;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// item is new
|
||||||
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeVideo;
|
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeVideo;
|
||||||
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
|
@ -1178,8 +1203,25 @@ namespace MediaBrowser.Controller.Entities
|
||||||
var newItemIds = newItems.Select(i => i.Id).ToArray();
|
var newItemIds = newItems.Select(i => i.Id).ToArray();
|
||||||
|
|
||||||
var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
|
var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
|
||||||
|
var ownerId = item.Id;
|
||||||
|
|
||||||
var tasks = newItems.Select(i => RefreshMetadataForOwnedItem(i, true, options, cancellationToken));
|
var tasks = newItems.Select(i =>
|
||||||
|
{
|
||||||
|
var subOptions = new MetadataRefreshOptions(options);
|
||||||
|
|
||||||
|
if (!i.ExtraType.HasValue ||
|
||||||
|
i.ExtraType.Value != Model.Entities.ExtraType.Trailer ||
|
||||||
|
i.OwnerId != ownerId ||
|
||||||
|
i.ParentId != Guid.Empty)
|
||||||
|
{
|
||||||
|
i.ExtraType = Model.Entities.ExtraType.Trailer;
|
||||||
|
i.OwnerId = ownerId;
|
||||||
|
i.ParentId = Guid.Empty;
|
||||||
|
subOptions.ForceSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
|
||||||
|
});
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -1196,13 +1238,20 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
|
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
|
||||||
|
|
||||||
|
var ownerId = item.Id;
|
||||||
|
|
||||||
var tasks = newThemeVideos.Select(i =>
|
var tasks = newThemeVideos.Select(i =>
|
||||||
{
|
{
|
||||||
var subOptions = new MetadataRefreshOptions(options);
|
var subOptions = new MetadataRefreshOptions(options);
|
||||||
|
|
||||||
if (!i.IsThemeMedia)
|
if (!i.ExtraType.HasValue ||
|
||||||
|
i.ExtraType.Value != Model.Entities.ExtraType.ThemeVideo ||
|
||||||
|
i.OwnerId != ownerId ||
|
||||||
|
i.ParentId != Guid.Empty)
|
||||||
{
|
{
|
||||||
i.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeVideo;
|
i.ExtraType = Model.Entities.ExtraType.ThemeVideo;
|
||||||
|
i.OwnerId = ownerId;
|
||||||
|
i.ParentId = Guid.Empty;
|
||||||
subOptions.ForceSave = true;
|
subOptions.ForceSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,13 +1275,20 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
|
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
|
||||||
|
|
||||||
|
var ownerId = item.Id;
|
||||||
|
|
||||||
var tasks = newThemeSongs.Select(i =>
|
var tasks = newThemeSongs.Select(i =>
|
||||||
{
|
{
|
||||||
var subOptions = new MetadataRefreshOptions(options);
|
var subOptions = new MetadataRefreshOptions(options);
|
||||||
|
|
||||||
if (!i.IsThemeMedia)
|
if (!i.ExtraType.HasValue ||
|
||||||
|
i.ExtraType.Value != Model.Entities.ExtraType.ThemeSong ||
|
||||||
|
i.OwnerId != ownerId ||
|
||||||
|
i.ParentId != Guid.Empty)
|
||||||
{
|
{
|
||||||
i.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeSong;
|
i.ExtraType = Model.Entities.ExtraType.ThemeSong;
|
||||||
|
i.OwnerId = ownerId;
|
||||||
|
i.ParentId = Guid.Empty;
|
||||||
subOptions.ForceSave = true;
|
subOptions.ForceSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1868,7 +1924,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
existingImage.Path = image.Path;
|
existingImage.Path = image.Path;
|
||||||
existingImage.DateModified = image.DateModified;
|
existingImage.DateModified = image.DateModified;
|
||||||
existingImage.IsPlaceholder = image.IsPlaceholder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -1902,7 +1957,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
image.Path = file.FullName;
|
image.Path = file.FullName;
|
||||||
image.DateModified = imageInfo.DateModified;
|
image.DateModified = imageInfo.DateModified;
|
||||||
image.IsPlaceholder = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2359,6 +2413,14 @@ namespace MediaBrowser.Controller.Entities
|
||||||
newOptions.ForceSave = true;
|
newOptions.ForceSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//var parentId = Id;
|
||||||
|
//if (!video.IsOwnedItem || video.ParentId != parentId)
|
||||||
|
//{
|
||||||
|
// video.IsOwnedItem = true;
|
||||||
|
// video.ParentId = parentId;
|
||||||
|
// newOptions.ForceSave = true;
|
||||||
|
//}
|
||||||
|
|
||||||
if (video == null)
|
if (video == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
|
|
|
@ -280,7 +280,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
FileInfo = FileSystem.GetDirectoryInfo(path),
|
FileInfo = FileSystem.GetDirectoryInfo(path),
|
||||||
Path = path,
|
Path = path,
|
||||||
Parent = Parent,
|
Parent = GetParent() as Folder,
|
||||||
CollectionType = CollectionType
|
CollectionType = CollectionType
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -378,6 +378,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var validChildren = new List<BaseItem>();
|
var validChildren = new List<BaseItem>();
|
||||||
|
var validChildrenNeedGeneration = false;
|
||||||
|
|
||||||
var allLibraryPaths = LibraryManager
|
var allLibraryPaths = LibraryManager
|
||||||
.GetVirtualFolders()
|
.GetVirtualFolders()
|
||||||
|
@ -474,11 +475,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (recursive || refreshChildMetadata)
|
validChildrenNeedGeneration = true;
|
||||||
{
|
|
||||||
// used below
|
|
||||||
validChildren = Children.ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Report(10);
|
progress.Report(10);
|
||||||
|
@ -502,6 +499,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
ProviderManager.OnRefreshProgress(folder, newPct);
|
ProviderManager.OnRefreshProgress(folder, newPct);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (validChildrenNeedGeneration)
|
||||||
|
{
|
||||||
|
validChildren = Children.ToList();
|
||||||
|
validChildrenNeedGeneration = false;
|
||||||
|
}
|
||||||
|
|
||||||
await ValidateSubFolders(validChildren.OfType<Folder>().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false);
|
await ValidateSubFolders(validChildren.OfType<Folder>().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,6 +539,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (validChildrenNeedGeneration)
|
||||||
|
{
|
||||||
|
validChildren = Children.ToList();
|
||||||
|
validChildrenNeedGeneration = false;
|
||||||
|
}
|
||||||
|
|
||||||
await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken);
|
await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,8 +596,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
|
await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (refreshOptions.RefreshItem(child))
|
||||||
{
|
{
|
||||||
await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (recursive)
|
if (recursive)
|
||||||
{
|
{
|
||||||
|
@ -1196,11 +1208,21 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// Gets the linked children.
|
/// Gets the linked children.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
public IEnumerable<BaseItem> GetLinkedChildren()
|
public List<BaseItem> GetLinkedChildren()
|
||||||
{
|
{
|
||||||
return LinkedChildren
|
var linkedChildren = LinkedChildren;
|
||||||
.Select(GetLinkedChild)
|
var list = new List<BaseItem>(linkedChildren.Length);
|
||||||
.Where(i => i != null);
|
|
||||||
|
foreach (var i in linkedChildren)
|
||||||
|
{
|
||||||
|
var child = GetLinkedChild(i);
|
||||||
|
|
||||||
|
if (child != null)
|
||||||
|
{
|
||||||
|
list.Add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool FilterLinkedChildrenPerUser
|
protected virtual bool FilterLinkedChildrenPerUser
|
||||||
|
@ -1211,16 +1233,19 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BaseItem> GetLinkedChildren(User user)
|
public List<BaseItem> GetLinkedChildren(User user)
|
||||||
{
|
{
|
||||||
if (!FilterLinkedChildrenPerUser || user == null)
|
if (!FilterLinkedChildrenPerUser || user == null)
|
||||||
{
|
{
|
||||||
return GetLinkedChildren();
|
return GetLinkedChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LinkedChildren.Length == 0)
|
var linkedChildren = LinkedChildren;
|
||||||
|
var list = new List<BaseItem>(linkedChildren.Length);
|
||||||
|
|
||||||
|
if (linkedChildren.Length == 0)
|
||||||
{
|
{
|
||||||
return new List<BaseItem>();
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
var allUserRootChildren = user.RootFolder.Children.OfType<Folder>().ToList();
|
var allUserRootChildren = user.RootFolder.Children.OfType<Folder>().ToList();
|
||||||
|
@ -1231,37 +1256,43 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.Select(i => i.Id)
|
.Select(i => i.Id)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return LinkedChildren
|
foreach (var i in linkedChildren)
|
||||||
.Select(i =>
|
|
||||||
{
|
{
|
||||||
var child = GetLinkedChild(i);
|
var child = GetLinkedChild(i);
|
||||||
|
|
||||||
if (child != null)
|
if (child == null)
|
||||||
{
|
{
|
||||||
var childLocationType = child.LocationType;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var childOwner = child.IsOwnedItem ? (child.GetOwner() ?? child) : child;
|
||||||
|
|
||||||
|
if (childOwner != null)
|
||||||
|
{
|
||||||
|
var childLocationType = childOwner.LocationType;
|
||||||
if (childLocationType == LocationType.Remote || childLocationType == LocationType.Virtual)
|
if (childLocationType == LocationType.Remote || childLocationType == LocationType.Virtual)
|
||||||
{
|
{
|
||||||
if (!child.IsVisibleStandalone(user))
|
if (!childOwner.IsVisibleStandalone(user))
|
||||||
{
|
{
|
||||||
return null;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (childLocationType == LocationType.FileSystem)
|
else if (childLocationType == LocationType.FileSystem)
|
||||||
{
|
{
|
||||||
var itemCollectionFolderIds =
|
var itemCollectionFolderIds =
|
||||||
LibraryManager.GetCollectionFolders(child, allUserRootChildren)
|
LibraryManager.GetCollectionFolders(childOwner, allUserRootChildren).Select(f => f.Id);
|
||||||
.Select(f => f.Id).ToList();
|
|
||||||
|
|
||||||
if (!itemCollectionFolderIds.Any(collectionFolderIds.Contains))
|
if (!itemCollectionFolderIds.Any(collectionFolderIds.Contains))
|
||||||
{
|
{
|
||||||
return null;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
list.Add(child);
|
||||||
})
|
}
|
||||||
.Where(i => i != null);
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Entities
|
namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
public interface IHasTrailers : IHasProviderIds
|
public interface IHasTrailers : IHasMetadata
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the remote trailers.
|
/// Gets or sets the remote trailers.
|
||||||
|
|
|
@ -24,12 +24,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <value>The date modified.</value>
|
/// <value>The date modified.</value>
|
||||||
public DateTime DateModified { get; set; }
|
public DateTime DateModified { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether this instance is placeholder.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance is placeholder; otherwise, <c>false</c>.</value>
|
|
||||||
public bool IsPlaceholder { get; set; }
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public bool IsLocalFile
|
public bool IsLocalFile
|
||||||
{
|
{
|
||||||
|
|
|
@ -81,7 +81,20 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||||
|
|
||||||
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
|
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
|
||||||
|
|
||||||
var tasks = newItems.Select(i => RefreshMetadataForOwnedItem(i, false, options, cancellationToken));
|
var ownerId = Id;
|
||||||
|
|
||||||
|
var tasks = newItems.Select(i =>
|
||||||
|
{
|
||||||
|
var subOptions = new MetadataRefreshOptions(options);
|
||||||
|
|
||||||
|
if (i.OwnerId != ownerId)
|
||||||
|
{
|
||||||
|
i.OwnerId = ownerId;
|
||||||
|
subOptions.ForceSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefreshMetadataForOwnedItem(i, false, subOptions, cancellationToken);
|
||||||
|
});
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,10 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (refreshOptions.RefreshItem(item))
|
||||||
|
{
|
||||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete;
|
double percent = numComplete;
|
||||||
|
@ -381,9 +384,12 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipItem)
|
if (!skipItem)
|
||||||
|
{
|
||||||
|
if (refreshOptions.RefreshItem(item))
|
||||||
{
|
{
|
||||||
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete;
|
double percent = numComplete;
|
||||||
|
|
|
@ -37,6 +37,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
public UserLinkType? ConnectLinkType { get; set; }
|
public UserLinkType? ConnectLinkType { get; set; }
|
||||||
public string ConnectAccessKey { get; set; }
|
public string ConnectAccessKey { get; set; }
|
||||||
|
|
||||||
|
// Strictly to remove IgnoreDataMember
|
||||||
|
public override ItemImageInfo[] ImageInfos { get => base.ImageInfos; set => base.ImageInfos = value; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the path.
|
/// Gets or sets the path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.IO;
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -20,6 +22,8 @@ namespace MediaBrowser.Controller.Providers
|
||||||
public MetadataRefreshMode MetadataRefreshMode { get; set; }
|
public MetadataRefreshMode MetadataRefreshMode { get; set; }
|
||||||
public RemoteSearchResult SearchResult { get; set; }
|
public RemoteSearchResult SearchResult { get; set; }
|
||||||
|
|
||||||
|
public List<string> RefreshPaths { get; set; }
|
||||||
|
|
||||||
public bool ForceSave { get; set; }
|
public bool ForceSave { get; set; }
|
||||||
|
|
||||||
public MetadataRefreshOptions(IFileSystem fileSystem)
|
public MetadataRefreshOptions(IFileSystem fileSystem)
|
||||||
|
@ -44,6 +48,26 @@ namespace MediaBrowser.Controller.Providers
|
||||||
ReplaceAllImages = copy.ReplaceAllImages;
|
ReplaceAllImages = copy.ReplaceAllImages;
|
||||||
ReplaceImages = copy.ReplaceImages.ToList();
|
ReplaceImages = copy.ReplaceImages.ToList();
|
||||||
SearchResult = copy.SearchResult;
|
SearchResult = copy.SearchResult;
|
||||||
|
|
||||||
|
if (copy.RefreshPaths != null && copy.RefreshPaths.Count > 0)
|
||||||
|
{
|
||||||
|
if (RefreshPaths == null)
|
||||||
|
{
|
||||||
|
RefreshPaths = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshPaths.AddRange(copy.RefreshPaths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RefreshItem(BaseItem item)
|
||||||
|
{
|
||||||
|
if (RefreshPaths != null && RefreshPaths.Count > 0)
|
||||||
|
{
|
||||||
|
return RefreshPaths.Contains(item.Path ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
MediaLocationsCreated = new string[] { };
|
MediaLocationsCreated = new string[] { };
|
||||||
RecordingEncodingFormat = "mkv";
|
RecordingEncodingFormat = "mkv";
|
||||||
RecordingPostProcessorArguments = "\"{path}\"";
|
RecordingPostProcessorArguments = "\"{path}\"";
|
||||||
EnableRecordingEncoding = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -66,9 +67,7 @@ namespace Priority_Queue
|
||||||
/// Removes every node from the queue.
|
/// Removes every node from the queue.
|
||||||
/// O(n) (So, don't do this often!)
|
/// O(n) (So, don't do this often!)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
Array.Clear(_nodes, 1, _numNodes);
|
Array.Clear(_nodes, 1, _numNodes);
|
||||||
|
@ -78,9 +77,7 @@ namespace Priority_Queue
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns (in O(1)!) whether the given node is in the queue. O(1)
|
/// Returns (in O(1)!) whether the given node is in the queue. O(1)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
public bool Contains(TItem node)
|
public bool Contains(TItem node)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -103,9 +100,7 @@ namespace Priority_Queue
|
||||||
/// If the node is already enqueued, the result is undefined.
|
/// If the node is already enqueued, the result is undefined.
|
||||||
/// O(log n)
|
/// O(log n)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
public void Enqueue(TItem node, TPriority priority)
|
public void Enqueue(TItem node, TPriority priority)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -131,9 +126,7 @@ namespace Priority_Queue
|
||||||
CascadeUp(_nodes[_numNodes]);
|
CascadeUp(_nodes[_numNodes]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
private void Swap(TItem node1, TItem node2)
|
private void Swap(TItem node1, TItem node2)
|
||||||
{
|
{
|
||||||
//Swap the nodes
|
//Swap the nodes
|
||||||
|
@ -164,9 +157,7 @@ namespace Priority_Queue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
private void CascadeDown(TItem node)
|
private void CascadeDown(TItem node)
|
||||||
{
|
{
|
||||||
//aka Heapify-down
|
//aka Heapify-down
|
||||||
|
@ -228,9 +219,7 @@ namespace Priority_Queue
|
||||||
/// Returns true if 'higher' has higher priority than 'lower', false otherwise.
|
/// Returns true if 'higher' has higher priority than 'lower', false otherwise.
|
||||||
/// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false
|
/// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
private bool HasHigherPriority(TItem higher, TItem lower)
|
private bool HasHigherPriority(TItem higher, TItem lower)
|
||||||
{
|
{
|
||||||
var cmp = higher.Priority.CompareTo(lower.Priority);
|
var cmp = higher.Priority.CompareTo(lower.Priority);
|
||||||
|
@ -319,9 +308,7 @@ namespace Priority_Queue
|
||||||
/// Calling this method on a node not in the queue results in undefined behavior
|
/// Calling this method on a node not in the queue results in undefined behavior
|
||||||
/// O(log n)
|
/// O(log n)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NET_VERSION_4_5
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#endif
|
|
||||||
public void UpdatePriority(TItem node, TPriority priority)
|
public void UpdatePriority(TItem node, TPriority priority)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
|
@ -206,8 +206,7 @@ namespace MediaBrowser.Providers.Manager
|
||||||
{
|
{
|
||||||
var image = item.GetImageInfo(type, 0);
|
var image = item.GetImageInfo(type, 0);
|
||||||
|
|
||||||
// if it's a placeholder image then pretend like it's not there so that we can replace it
|
return image != null;
|
||||||
return image != null && !image.IsPlaceholder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -547,7 +546,7 @@ namespace MediaBrowser.Providers.Manager
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ImageType.Primary:
|
case ImageType.Primary:
|
||||||
return !(item is Movie || item is Series || item is Game);
|
return true;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,8 +262,7 @@ namespace MediaBrowser.Providers.Manager
|
||||||
personEntity.SetImage(new ItemImageInfo
|
personEntity.SetImage(new ItemImageInfo
|
||||||
{
|
{
|
||||||
Path = imageUrl,
|
Path = imageUrl,
|
||||||
Type = ImageType.Primary,
|
Type = ImageType.Primary
|
||||||
IsPlaceholder = true
|
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
return _cachedTask;
|
return _cachedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!item.IsCompleteMedia)
|
||||||
|
{
|
||||||
|
return _cachedTask;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.IsShortcut)
|
if (item.IsShortcut)
|
||||||
{
|
{
|
||||||
FetchShortcutInfo(item);
|
FetchShortcutInfo(item);
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
var video = item as Video;
|
var video = item as Video;
|
||||||
|
|
||||||
if (item.LocationType == LocationType.FileSystem && video != null && !video.IsPlaceHolder && !video.IsShortcut)
|
if (item.LocationType == LocationType.FileSystem && video != null && !video.IsPlaceHolder && !video.IsShortcut && video.IsCompleteMedia)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("3.2.30.24")]
|
[assembly: AssemblyVersion("3.2.30.25")]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user