diff options
Diffstat (limited to 'Emby.Server.Implementations')
38 files changed, 422 insertions, 556 deletions
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 73878160c..2adf6a37c 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -23,19 +23,21 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; - +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.Channels { public class ChannelManager : IChannelManager { - private IChannel[] _channels; + internal IChannel[] Channels { get; private set; } private readonly IUserManager _userManager; private readonly IUserDataManager _userDataManager; @@ -76,12 +78,12 @@ namespace Emby.Server.Implementations.Channels public void AddParts(IEnumerable<IChannel> channels) { - _channels = channels.ToArray(); + Channels = channels.ToArray(); } private IEnumerable<IChannel> GetAllChannels() { - return _channels + return Channels .OrderBy(i => i.Name); } @@ -980,7 +982,7 @@ namespace Emby.Server.Implementations.Channels ? null : _userManager.GetUserById(query.UserId); - var internalResult = await GetChannelItemsInternal(query, new Progress<double>(), cancellationToken).ConfigureAwait(false); + var internalResult = await GetChannelItemsInternal(query, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); var dtoOptions = new DtoOptions() { @@ -1559,4 +1561,76 @@ namespace Emby.Server.Implementations.Channels return await _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false); } } + + public class ChannelsEntryPoint : IServerEntryPoint + { + private readonly IServerConfigurationManager _config; + private readonly IChannelManager _channelManager; + private readonly ITaskManager _taskManager; + private readonly IFileSystem _fileSystem; + + public ChannelsEntryPoint(IChannelManager channelManager, ITaskManager taskManager, IServerConfigurationManager config, IFileSystem fileSystem) + { + _channelManager = channelManager; + _taskManager = taskManager; + _config = config; + _fileSystem = fileSystem; + } + + public void Run() + { + var channels = ((ChannelManager)_channelManager).Channels + .Select(i => i.GetType().FullName.GetMD5().ToString("N")) + .ToArray(); + + var channelsString = string.Join(",", channels); + + if (!string.Equals(channelsString, GetSavedLastChannels(), StringComparison.OrdinalIgnoreCase)) + { + _taskManager.QueueIfNotRunning<RefreshChannelsScheduledTask>(); + + SetSavedLastChannels(channelsString); + } + } + + private string DataPath + { + get { return Path.Combine(_config.ApplicationPaths.DataPath, "channels.txt"); } + } + + private string GetSavedLastChannels() + { + try + { + return _fileSystem.ReadAllText(DataPath); + } + catch + { + return string.Empty; + } + } + + private void SetSavedLastChannels(string value) + { + try + { + if (string.IsNullOrWhiteSpace(value)) + { + _fileSystem.DeleteFile(DataPath); + + } + else + { + _fileSystem.WriteAllText(DataPath, value); + } + } + catch + { + } + } + + public void Dispose() + { + } + } }
\ No newline at end of file diff --git a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs index aef06bd1d..ae31fcf3f 100644 --- a/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs +++ b/Emby.Server.Implementations/Channels/ChannelPostScanTask.cs @@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Channels StartIndex = totalRetrieved, FolderId = folderId - }, new Progress<double>(), cancellationToken); + }, new SimpleProgress<double>(), cancellationToken); folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N"))); diff --git a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs index d5ec86445..4a3301252 100644 --- a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.Channels @@ -42,7 +43,7 @@ namespace Emby.Server.Implementations.Channels { var manager = (ChannelManager)_channelManager; - await manager.RefreshChannels(new Progress<double>(), cancellationToken).ConfigureAwait(false); + await manager.RefreshChannels(new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); await new ChannelPostScanTask(_channelManager, _userManager, _logger, _libraryManager).Run(progress, cancellationToken) .ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index e25955782..df8d1ac45 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -56,24 +56,9 @@ namespace Emby.Server.Implementations.Data var rootChildren = _libraryManager.RootFolder.Children.ToList(); rootChildren = _libraryManager.GetUserRootFolder().Children.ToList(); - var innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => - { - double newPercentCommplete = .45 * p; - progress.Report(newPercentCommplete); - }); - await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); - progress.Report(45); - - innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => - { - double newPercentCommplete = 45 + .55 * p; - progress.Report(newPercentCommplete); - }); + await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false); - await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false); - progress.Report(100); + //await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false); } private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index df3cecbf9..52abbae3e 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -3758,10 +3758,10 @@ namespace Emby.Server.Implementations.Data if (query.MinDateLastSavedForUser.HasValue) { - whereClauses.Add("DateLastSaved>=@MinDateLastSaved"); + whereClauses.Add("DateLastSaved>=@MinDateLastSavedForUser"); if (statement != null) { - statement.TryBind("@MinDateLastSaved", query.MinDateLastSavedForUser.Value); + statement.TryBind("@MinDateLastSavedForUser", query.MinDateLastSavedForUser.Value); } } @@ -3929,15 +3929,6 @@ namespace Emby.Server.Implementations.Data } } - if (!string.IsNullOrWhiteSpace(query.SlugName)) - { - whereClauses.Add("CleanName=@SlugName"); - if (statement != null) - { - statement.TryBind("@SlugName", GetCleanValue(query.SlugName)); - } - } - if (!string.IsNullOrWhiteSpace(query.MinSortName)) { whereClauses.Add("SortName>=@MinSortName"); @@ -4306,12 +4297,9 @@ namespace Emby.Server.Implementations.Data } } - if (query.HasDeadParentId.HasValue) + if (query.HasDeadParentId.HasValue && query.HasDeadParentId.Value) { - if (query.HasDeadParentId.Value) - { - whereClauses.Add("ParentId NOT NULL AND ParentId NOT IN (select guid from TypedBaseItems)"); - } + whereClauses.Add("ParentId NOT NULL AND ParentId NOT IN (select guid from TypedBaseItems)"); } if (query.Years.Length == 1) diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 6bf58455f..9767de9e0 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -105,9 +105,13 @@ namespace Emby.Server.Implementations.Dto var programTuples = new List<Tuple<BaseItem, BaseItemDto>>(); var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>>(); + var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) + ? _providerManager.GetRefreshQueue() + : null; + foreach (var item in items) { - var dto = GetBaseItemDtoInternal(item, options, user, owner); + var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner); var tvChannel = item as LiveTvChannel; if (tvChannel != null) @@ -160,7 +164,11 @@ namespace Emby.Server.Implementations.Dto { var syncDictionary = GetSyncedItemProgress(options); - var dto = GetBaseItemDtoInternal(item, options, user, owner); + var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) + ? _providerManager.GetRefreshQueue() + : null; + + var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner); var tvChannel = item as LiveTvChannel; if (tvChannel != null) { @@ -292,7 +300,7 @@ namespace Emby.Server.Implementations.Dto } } - private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary<Guid, Guid> currentRefreshQueue, User user = null, BaseItem owner = null) { var fields = options.Fields; @@ -392,6 +400,11 @@ namespace Emby.Server.Implementations.Dto dto.Etag = item.GetEtag(user); } + if (currentRefreshQueue != null) + { + //dto.RefreshState = item.GetRefreshState(currentRefreshQueue); + } + if (item is ILiveTvRecording) { _livetvManager().AddInfoToRecordingDto(item, dto, user); @@ -402,7 +415,10 @@ namespace Emby.Server.Implementations.Dto public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null) { - var dto = GetBaseItemDtoInternal(item, options, user); + var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) + ? _providerManager.GetRefreshQueue() + : null; + var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user); if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts)) { @@ -778,16 +794,16 @@ namespace Emby.Server.Implementations.Dto .Select(i => new NameIdPair { Name = i, - Id = GetStudioId(i, item) + Id = GetGenreId(i, item) }) .ToArray(); } - private string GetStudioId(string name, BaseItem owner) + private string GetGenreId(string name, BaseItem owner) { if (owner is IHasMusicGenres) { - return _libraryManager.GetGameGenreId(name).ToString("N"); + return _libraryManager.GetMusicGenreId(name).ToString("N"); } if (owner is Game || owner is GameSystem) @@ -1058,18 +1074,8 @@ namespace Emby.Server.Implementations.Dto dto.CommunityRating = item.CommunityRating; } - //if (item.IsFolder) - //{ - // var folder = (Folder)item; - - // if (fields.Contains(ItemFields.IndexOptions)) - // { - // dto.IndexOptions = folder.IndexByOptionStrings.ToArray(); - // } - //} - var supportsPlaceHolders = item as ISupportsPlaceHolders; - if (supportsPlaceHolders != null) + if (supportsPlaceHolders != null && supportsPlaceHolders.IsPlaceHolder) { dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder; } @@ -1458,9 +1464,9 @@ namespace Emby.Server.Implementations.Dto } } - private BaseItem GetImageDisplayParent(BaseItem item) + private BaseItem GetImageDisplayParent(BaseItem currentItem, BaseItem originalItem) { - var musicAlbum = item as MusicAlbum; + var musicAlbum = currentItem as MusicAlbum; if (musicAlbum != null) { var artist = musicAlbum.GetMusicArtist(new DtoOptions(false)); @@ -1470,7 +1476,14 @@ namespace Emby.Server.Implementations.Dto } } - return item.DisplayParent ?? item.GetParent(); + var parent = currentItem.DisplayParent ?? currentItem.GetParent(); + + if (parent == null && !(originalItem is UserRootFolder) && !(originalItem is UserView) && !(originalItem is AggregateFolder) && !(originalItem is ICollectionFolder) && !(originalItem is Channel)) + { + parent = _libraryManager.GetCollectionFolders(originalItem).FirstOrDefault(); + } + + return parent; } private void AddInheritedImages(BaseItemDto dto, BaseItem item, DtoOptions options, BaseItem owner) @@ -1497,7 +1510,7 @@ namespace Emby.Server.Implementations.Dto var isFirst = true; while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) && - (parent = parent ?? (isFirst ? GetImageDisplayParent(item) ?? owner : parent)) != null) + (parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null) { if (parent == null) { @@ -1554,7 +1567,7 @@ namespace Emby.Server.Implementations.Dto break; } - parent = GetImageDisplayParent(parent); + parent = GetImageDisplayParent(parent, item); } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index df70680f1..5486f404f 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -148,7 +148,6 @@ <Compile Include="Library\Validators\PeopleValidator.cs" /> <Compile Include="Library\Validators\StudiosPostScanTask.cs" /> <Compile Include="Library\Validators\StudiosValidator.cs" /> - <Compile Include="Library\Validators\YearsPostScanTask.cs" /> <Compile Include="LiveTv\ChannelImageProvider.cs" /> <Compile Include="LiveTv\EmbyTV\DirectRecorder.cs" /> <Compile Include="LiveTv\EmbyTV\EmbyTV.cs" /> @@ -167,7 +166,6 @@ <Compile Include="LiveTv\LiveTvDtoService.cs" /> <Compile Include="LiveTv\LiveTvManager.cs" /> <Compile Include="LiveTv\LiveTvMediaSourceProvider.cs" /> - <Compile Include="LiveTv\ProgramImageProvider.cs" /> <Compile Include="LiveTv\RecordingImageProvider.cs" /> <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" /> <Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" /> @@ -183,8 +181,6 @@ <Compile Include="Logging\UnhandledExceptionWriter.cs" /> <Compile Include="MediaEncoder\EncodingManager.cs" /> <Compile Include="Migrations\IVersionMigration.cs" /> - <Compile Include="Migrations\LibraryScanMigration.cs" /> - <Compile Include="Migrations\GuideMigration.cs" /> <Compile Include="News\NewsEntryPoint.cs" /> <Compile Include="News\NewsService.cs" /> <Compile Include="Notifications\CoreNotificationTypes.cs" /> @@ -206,7 +202,6 @@ <Compile Include="ScheduledTasks\ChapterImagesTask.cs" /> <Compile Include="ScheduledTasks\PeopleValidationTask.cs" /> <Compile Include="ScheduledTasks\PluginUpdateTask.cs" /> - <Compile Include="ScheduledTasks\RefreshIntrosTask.cs" /> <Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" /> <Compile Include="ScheduledTasks\SystemUpdateTask.cs" /> <Compile Include="Security\AuthenticationRepository.cs" /> @@ -297,8 +292,8 @@ <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project> <Name>SocketHttpListener</Name> </ProjectReference> - <Reference Include="Emby.XmlTv, Version=1.0.6299.28292, Culture=neutral, processorArchitecture=MSIL"> - <HintPath>..\packages\Emby.XmlTv.1.0.8\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath> + <Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="MediaBrowser.Naming, Version=1.0.6279.25941, Culture=neutral, processorArchitecture=MSIL"> @@ -309,12 +304,12 @@ <HintPath>..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll</HintPath> <Private>True</Private> </Reference> + </ItemGroup> + <ItemGroup> <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL"> - <HintPath>..\packages\SQLitePCLRaw.core.1.1.5\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath> + <HintPath>..\packages\SQLitePCLRaw.core.1.1.6\lib\net45\SQLitePCLRaw.core.dll</HintPath> <Private>True</Private> </Reference> - </ItemGroup> - <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Runtime.Serialization" /> diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 91142f928..69a205dda 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -6,9 +6,14 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Threading; @@ -49,13 +54,16 @@ namespace Emby.Server.Implementations.EntryPoints /// </summary> private const int LibraryUpdateDuration = 5000; - public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory) + private readonly IProviderManager _providerManager; + + public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory, IProviderManager providerManager) { _libraryManager = libraryManager; _sessionManager = sessionManager; _userManager = userManager; _logger = logger; _timerFactory = timerFactory; + _providerManager = providerManager; } public void Run() @@ -64,6 +72,106 @@ namespace Emby.Server.Implementations.EntryPoints _libraryManager.ItemUpdated += libraryManager_ItemUpdated; _libraryManager.ItemRemoved += libraryManager_ItemRemoved; + _providerManager.RefreshCompleted += _providerManager_RefreshCompleted; + _providerManager.RefreshStarted += _providerManager_RefreshStarted; + _providerManager.RefreshProgress += _providerManager_RefreshProgress; + } + + private Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>(); + + private void _providerManager_RefreshProgress(object sender, GenericEventArgs<Tuple<BaseItem, double>> e) + { + var item = e.Argument.Item1; + + if (!EnableRefreshMessage(item)) + { + return; + } + + var progress = e.Argument.Item2; + + DateTime lastMessageSendTime; + if (_lastProgressMessageTimes.TryGetValue(item.Id, out lastMessageSendTime)) + { + if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000) + { + return; + } + } + + _lastProgressMessageTimes[item.Id] = DateTime.UtcNow; + + var dict = new Dictionary<string, string>(); + dict["ItemId"] = item.Id.ToString("N"); + dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture); + + try + { + _sessionManager.SendMessageToAdminSessions("RefreshProgress", dict, CancellationToken.None); + } + catch + { + } + + var collectionFolders = _libraryManager.GetCollectionFolders(item).ToList(); + + foreach (var collectionFolder in collectionFolders) + { + var collectionFolderDict = new Dictionary<string, string>(); + collectionFolderDict["ItemId"] = collectionFolder.Id.ToString("N"); + collectionFolderDict["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture); + + try + { + _sessionManager.SendMessageToAdminSessions("RefreshProgress", collectionFolderDict, CancellationToken.None); + } + catch + { + + } + } + } + + private void _providerManager_RefreshStarted(object sender, GenericEventArgs<BaseItem> e) + { + _providerManager_RefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0))); + } + + private void _providerManager_RefreshCompleted(object sender, GenericEventArgs<BaseItem> e) + { + _providerManager_RefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100))); + } + + private bool EnableRefreshMessage(BaseItem item) + { + var folder = item as Folder; + + if (folder == null) + { + return false; + } + + if (folder.IsRoot) + { + return false; + } + + if (folder is AggregateFolder || folder is UserRootFolder) + { + return false; + } + + if (folder is UserView || folder is Channel) + { + return false; + } + + if (!folder.IsTopParent) + { + return false; + } + + return true; } /// <summary> @@ -218,8 +326,8 @@ namespace Emby.Server.Implementations.EntryPoints try { - info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, - foldersRemovedFrom, id); + info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, + foldersRemovedFrom, id); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 79209d438..28c23b766 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -598,9 +598,10 @@ namespace Emby.Server.Implementations.HttpServer { ErrorHandler(ex, httpReq, false); } + catch (Exception ex) { - ErrorHandler(ex, httpReq); + ErrorHandler(ex, httpReq, !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase)); } finally { diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs index 57eef5db0..ac36f8f51 100644 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs @@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.HttpServer { if (!hasHeaders.Headers.ContainsKey("Server")) { - hasHeaders.Headers["Server"] = "Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50"; + hasHeaders.Headers["Server"] = "Microsoft-NetCore/2.0, UPnP/1.0 DLNADOC/1.50"; //hasHeaders.Headers["Server"] = "Mono-HTTPAPI/1.1"; } diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 9606b60b8..d4914e734 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -170,7 +170,7 @@ namespace Emby.Server.Implementations.IO // If the root folder changed, run the library task so the user can see it if (itemsToRefresh.Any(i => i is AggregateFolder)) { - LibraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); + LibraryManager.ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None); return; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index a08c74474..4846a5768 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -462,7 +462,7 @@ namespace Emby.Server.Implementations.Library if (parent != null) { - await parent.ValidateChildren(new Progress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false); + await parent.ValidateChildren(new SimpleProgress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false); } } else if (parent != null) @@ -1113,13 +1113,13 @@ namespace Emby.Server.Implementations.Library progress.Report(.5); // Start by just validating the children of the root, but go no further - await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false); + await RootFolder.ValidateChildren(new SimpleProgress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false); progress.Report(1); await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false); - await GetUserRootFolder().ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false); + await GetUserRootFolder().ValidateChildren(new SimpleProgress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false); progress.Report(2); // Quickly scan CollectionFolders for changes @@ -1204,25 +1204,24 @@ namespace Emby.Server.Implementations.Library /// Gets the default view. /// </summary> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - public IEnumerable<VirtualFolderInfo> GetVirtualFolders() + public List<VirtualFolderInfo> GetVirtualFolders() { - return GetView(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath); + return GetVirtualFolders(false); } - /// <summary> - /// Gets the view. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - private IEnumerable<VirtualFolderInfo> GetView(string path) + public List<VirtualFolderInfo> GetVirtualFolders(bool includeRefreshState) { var topLibraryFolders = GetUserRootFolder().Children.ToList(); - return _fileSystem.GetDirectoryPaths(path) - .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders)); + var refreshQueue = includeRefreshState ? _providerManagerFactory().GetRefreshQueue() : null; + + return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath) + .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue)) + .OrderBy(i => i.Name) + .ToList(); } - private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders) + private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders, Dictionary<Guid, Guid> refreshQueue) { var info = new VirtualFolderInfo { @@ -1248,6 +1247,13 @@ namespace Emby.Server.Implementations.Library { info.ItemId = libraryFolder.Id.ToString("N"); info.LibraryOptions = GetLibraryOptions(libraryFolder); + + if (refreshQueue != null) + { + info.RefreshProgress = libraryFolder.GetRefreshProgress(); + + info.RefreshStatus = info.RefreshProgress.HasValue ? "Active" : refreshQueue.ContainsKey(libraryFolder.Id) ? "Queued" : "Idle"; + } } return info; @@ -2359,7 +2365,7 @@ namespace Emby.Server.Implementations.Library public bool IsVideoFile(string path, LibraryOptions libraryOptions) { - var resolver = new VideoResolver(GetNamingOptions(libraryOptions), new NullLogger()); + var resolver = new VideoResolver(GetNamingOptions(), new NullLogger()); return resolver.IsVideoFile(path); } @@ -2370,7 +2376,7 @@ namespace Emby.Server.Implementations.Library public bool IsAudioFile(string path, LibraryOptions libraryOptions) { - var parser = new AudioFileParser(GetNamingOptions(libraryOptions)); + var parser = new AudioFileParser(GetNamingOptions()); return parser.IsAudioFile(path); } @@ -2505,34 +2511,42 @@ namespace Emby.Server.Implementations.Library public NamingOptions GetNamingOptions() { - return GetNamingOptions(new LibraryOptions()); + return GetNamingOptions(true); } + public NamingOptions GetNamingOptions(bool allowOptimisticEpisodeDetection) + { + if (!allowOptimisticEpisodeDetection) + { + if (_namingOptionsWithoutOptimisticEpisodeDetection == null) + { + var namingOptions = new ExtendedNamingOptions(); + + InitNamingOptions(namingOptions); + namingOptions.EpisodeExpressions = namingOptions.EpisodeExpressions + .Where(i => i.IsNamed && !i.IsOptimistic) + .ToList(); + + _namingOptionsWithoutOptimisticEpisodeDetection = namingOptions; + } + + return _namingOptionsWithoutOptimisticEpisodeDetection; + } + + return GetNamingOptionsInternal(); + } + + private NamingOptions _namingOptionsWithoutOptimisticEpisodeDetection; private NamingOptions _namingOptions; private string[] _videoFileExtensions; - public NamingOptions GetNamingOptions(LibraryOptions libraryOptions) + private NamingOptions GetNamingOptionsInternal() { if (_namingOptions == null) { var options = new ExtendedNamingOptions(); - // These cause apps to have problems - options.AudioFileExtensions.Remove(".m3u"); - options.AudioFileExtensions.Remove(".wpl"); - - //if (!libraryOptions.EnableArchiveMediaFiles) - { - options.AudioFileExtensions.Remove(".rar"); - options.AudioFileExtensions.Remove(".zip"); - } + InitNamingOptions(options); - //if (!libraryOptions.EnableArchiveMediaFiles) - { - options.VideoFileExtensions.Remove(".rar"); - options.VideoFileExtensions.Remove(".zip"); - } - - options.VideoFileExtensions.Add(".tp"); _namingOptions = options; _videoFileExtensions = _namingOptions.VideoFileExtensions.ToArray(); } @@ -2540,6 +2554,27 @@ namespace Emby.Server.Implementations.Library return _namingOptions; } + private void InitNamingOptions(NamingOptions options) + { + // These cause apps to have problems + options.AudioFileExtensions.Remove(".m3u"); + options.AudioFileExtensions.Remove(".wpl"); + + //if (!libraryOptions.EnableArchiveMediaFiles) + { + options.AudioFileExtensions.Remove(".rar"); + options.AudioFileExtensions.Remove(".zip"); + } + + //if (!libraryOptions.EnableArchiveMediaFiles) + { + options.VideoFileExtensions.Remove(".rar"); + options.VideoFileExtensions.Remove(".zip"); + } + + options.VideoFileExtensions.Add(".tp"); + } + public ItemLookupInfo ParseName(string name) { var resolver = new VideoResolver(GetNamingOptions(), new NullLogger()); @@ -2918,7 +2953,7 @@ namespace Emby.Server.Implementations.Library // No need to start if scanning the library because it will handle it if (refreshLibrary) { - ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); + ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None); } else { @@ -3046,7 +3081,7 @@ namespace Emby.Server.Implementations.Library private void SyncLibraryOptionsToLocations(string virtualFolderPath, LibraryOptions options) { var topLibraryFolders = GetUserRootFolder().Children.ToList(); - var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders); + var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders, null); if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length) { @@ -3096,7 +3131,7 @@ namespace Emby.Server.Implementations.Library // No need to start if scanning the library because it will handle it if (refreshLibrary) { - ValidateMediaLibrary(new Progress<double>(), CancellationToken.None); + ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None); } else { diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs index 2e3d81474..e2f2946db 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; using MediaBrowser.Controller.Entities; +using System.IO; namespace Emby.Server.Implementations.Library.Resolvers.Audio { @@ -42,6 +43,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio if (_libraryManager.IsAudioFile(args.Path, libraryOptions)) { + if (string.Equals(Path.GetExtension(args.Path), ".cue", StringComparison.OrdinalIgnoreCase)) + { + // if audio file exists of same name, return null + + return null; + } + var collectionType = args.GetCollectionType(); var isMixed = string.IsNullOrWhiteSpace(collectionType); diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 806e20f00..70fe8d9ef 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions) { - var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(libraryOptions); + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var parser = new AlbumParser(namingOptions, new NullLogger()); var result = parser.ParseMultiPart(path); diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 60260e98a..e1c18c913 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -160,15 +160,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV return true; } - var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions(); - - // In mixed folders we need to be conservative and avoid expressions that may result in false positives (e.g. movies with numbers in the title) - if (!isTvContentType) - { - namingOptions.EpisodeExpressions = namingOptions.EpisodeExpressions - .Where(i => i.IsNamed && !i.IsOptimistic) - .ToList(); - } + var allowOptimisticEpisodeDetection = isTvContentType; + var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions(allowOptimisticEpisodeDetection); var episodeResolver = new MediaBrowser.Naming.TV.EpisodeResolver(namingOptions, new NullLogger()); var episodeInfo = episodeResolver.Resolve(fullName, false, false); diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs index d4be2dabe..1a53ad672 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -2,11 +2,14 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Persistence; namespace Emby.Server.Implementations.Library.Validators @@ -78,6 +81,35 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(percent); } + names = names.Select(i => i.RemoveDiacritics()).DistinctNames().ToList(); + + var artistEntities = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(MusicArtist).Name } + + }).Cast<MusicArtist>().ToList(); + + foreach (var artist in artistEntities) + { + if (!artist.IsAccessedByName) + { + continue; + } + + var name = (artist.Name ?? string.Empty).RemoveDiacritics(); + + if (!names.Contains(name, StringComparer.OrdinalIgnoreCase)) + { + _logger.Info("Deleting dead artist {0} {1}.", artist.Id.ToString("N"), artist.Name); + + await _libraryManager.DeleteItem(artist, new DeleteOptions + { + DeleteFileLocation = false + + }).ConfigureAwait(false); + } + } + progress.Report(100); } } diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index ef3b86abf..c2eb30ee4 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -55,10 +55,6 @@ namespace Emby.Server.Implementations.Library.Validators /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress) { - var innerProgress = new ActionableProgress<double>(); - - innerProgress.RegisterAction(pct => progress.Report(pct * .15)); - var people = _libraryManager.GetPeople(new InternalPeopleQuery()); var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); diff --git a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs deleted file mode 100644 index 4afb4c04a..000000000 --- a/Emby.Server.Implementations/Library/Validators/YearsPostScanTask.cs +++ /dev/null @@ -1,57 +0,0 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Emby.Server.Implementations.Library.Validators -{ - public class YearsPostScanTask : ILibraryPostScanTask - { - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - - public YearsPostScanTask(ILibraryManager libraryManager, ILogger logger) - { - _libraryManager = libraryManager; - _logger = logger; - } - - public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - var yearNumber = 1900; - var maxYear = DateTime.UtcNow.Year + 3; - var count = maxYear - yearNumber + 1; - var numComplete = 0; - - while (yearNumber < maxYear) - { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - var year = _libraryManager.GetYear(yearNumber); - - await year.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error refreshing year {0}", ex, yearNumber); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); - yearNumber++; - } - } - } -} diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index a4c5b338e..b55e4412b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -28,7 +28,7 @@ using System.Xml; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; - +using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -240,7 +240,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (requiresRefresh) { - _libraryManager.ValidateMediaLibrary(new Progress<Double>(), CancellationToken.None); + _libraryManager.ValidateMediaLibrary(new SimpleProgress<Double>(), CancellationToken.None); } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index bba625cd1..e12acf140 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -174,7 +174,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList(); var imagesWithoutText = allImages.Where(i => string.Equals(i.text, "no", StringComparison.OrdinalIgnoreCase)).ToList(); - double desiredAspect = IsMovie(programEntry) ? 0.666666667 : wideAspect; + double desiredAspect = 0.666666667; programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, true, desiredAspect) ?? GetProgramImage(ApiUrl, allImages, true, desiredAspect); @@ -237,8 +237,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private bool IsMovie(ScheduleDirect.ProgramDetails programInfo) { - var showType = programInfo.showType ?? string.Empty; - return showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1; + return string.Equals(programInfo.entityType, "movie", StringComparison.OrdinalIgnoreCase); } private ProgramInfo GetProgram(string channelId, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details) @@ -280,8 +279,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings episodeTitle = details.episodeTitle150; } - var showType = details.showType ?? string.Empty; - var info = new ProgramInfo { ChannelId = channelId, @@ -294,11 +291,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings EpisodeTitle = episodeTitle, Audio = audioType, IsRepeat = repeat, - IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, + IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase), ImageUrl = details.primaryImage, ThumbImageUrl = details.thumbImage, IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), - IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, + IsSports = string.Equals(details.entityType, "sports", StringComparison.OrdinalIgnoreCase), IsMovie = IsMovie(details), Etag = programInfo.md5 }; @@ -882,7 +879,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings foreach (ScheduleDirect.Map map in root.map) { var channelNumber = GetChannelNumber(map); - + var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); if (station == null) { @@ -906,7 +903,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { channelInfo.Name = station.name; } - + channelInfo.Id = station.stationID; channelInfo.CallSign = station.callsign; @@ -1199,6 +1196,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings public List<ContentRating> contentRating { get; set; } public List<Cast> cast { get; set; } public List<Crew> crew { get; set; } + public string entityType { get; set; } public string showType { get; set; } public bool hasImageArtwork { get; set; } public string primaryImage { get; set; } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index b50f5ac92..fb8308cda 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -15,6 +15,7 @@ using Emby.XmlTv.Classes; using Emby.XmlTv.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -48,8 +49,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings get { return "xmltv"; } } - private string GetLanguage() + private string GetLanguage(ListingsProviderInfo info) { + if (!string.IsNullOrWhiteSpace(info.PreferredLanguage)) + { + return info.PreferredLanguage; + } + return _config.Configuration.PreferredMetadataLanguage; } @@ -75,7 +81,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { CancellationToken = cancellationToken, Url = path, - Progress = new Progress<Double>(), + Progress = new SimpleProgress<Double>(), DecompressionMethod = CompressionMethod.Gzip, // It's going to come back gzipped regardless of this value @@ -151,7 +157,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings _logger.Debug("Getting xmltv programs for channel {0}", channelId); var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); - var reader = new XmlTvReader(path, GetLanguage()); + var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken); return results.Select(p => GetProgramInfo(p, info)); @@ -253,7 +259,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false); - var reader = new XmlTvReader(path, GetLanguage()); + var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); // Should this method be async? @@ -264,7 +270,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); - var reader = new XmlTvReader(path, GetLanguage()); + var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); // Should this method be async? diff --git a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs index 12da1464b..428b6202b 100644 --- a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs @@ -16,7 +16,8 @@ namespace Emby.Server.Implementations.LiveTv private readonly IMediaEncoder _mediaEncoder; private readonly ILogger _logger; - const int AnalyzeDurationMs = 1000; + const int ProbeAnalyzeDurationMs = 2000; + const int PlaybackAnalyzeDurationMs = 2000; public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger) { @@ -36,7 +37,7 @@ namespace Emby.Server.Implementations.LiveTv Protocol = mediaSource.Protocol, MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, ExtractChapters = false, - AnalyzeDurationMs = AnalyzeDurationMs + AnalyzeDurationMs = ProbeAnalyzeDurationMs }, cancellationToken).ConfigureAwait(false); @@ -106,7 +107,7 @@ namespace Emby.Server.Implementations.LiveTv // Try to estimate this mediaSource.InferTotalBitrate(true); - mediaSource.AnalyzeDurationMs = AnalyzeDurationMs; + mediaSource.AnalyzeDurationMs = PlaybackAnalyzeDurationMs; } } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 4ad411c19..24afc03da 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -742,7 +742,7 @@ namespace Emby.Server.Implementations.LiveTv else { // Increment this whenver some internal change deems it necessary - var etag = info.Etag + "4"; + var etag = info.Etag + "6"; if (!string.Equals(etag, item.ExternalEtag, StringComparison.OrdinalIgnoreCase)) { @@ -1273,8 +1273,8 @@ namespace Emby.Server.Implementations.LiveTv if (coreService != null) { - await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false); - await coreService.RefreshTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false); + await coreService.RefreshSeriesTimers(cancellationToken, new SimpleProgress<double>()).ConfigureAwait(false); + await coreService.RefreshTimers(cancellationToken, new SimpleProgress<double>()).ConfigureAwait(false); } // Load these now which will prefetch metadata @@ -1422,15 +1422,6 @@ namespace Emby.Server.Implementations.LiveTv await _libraryManager.UpdateItem(program, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } - foreach (var program in newPrograms) - { - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Low); - } - foreach (var program in updatedPrograms) - { - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Low); - } - currentChannel.IsMovie = isMovie; currentChannel.IsNews = isNews; currentChannel.IsSports = isSports; @@ -1558,7 +1549,7 @@ namespace Emby.Server.Implementations.LiveTv var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false); - await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new Progress<double>(), cancellationToken).ConfigureAwait(false); + await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); _lastRecordingRefreshTime = DateTime.UtcNow; } diff --git a/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs b/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs deleted file mode 100644 index 5cff88a67..000000000 --- a/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs +++ /dev/null @@ -1,103 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace Emby.Server.Implementations.LiveTv -{ - public class ProgramImageProvider : IDynamicImageProvider, IHasItemChangeMonitor, IHasOrder - { - private readonly ILiveTvManager _liveTvManager; - - public ProgramImageProvider(ILiveTvManager liveTvManager) - { - _liveTvManager = liveTvManager; - } - - public IEnumerable<ImageType> GetSupportedImages(IHasImages item) - { - return new[] { ImageType.Primary }; - } - - private string GetItemExternalId(BaseItem item) - { - var externalId = item.ExternalId; - - if (string.IsNullOrWhiteSpace(externalId)) - { - externalId = item.GetProviderId("ProviderExternalId"); - } - - return externalId; - } - - public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken) - { - var liveTvItem = (LiveTvProgram)item; - - var imageResponse = new DynamicImageResponse(); - - var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase)); - - if (service != null) - { - try - { - var channel = _liveTvManager.GetInternalChannel(liveTvItem.ChannelId); - - if (channel != null) - { - var response = await service.GetProgramImageAsync(GetItemExternalId(liveTvItem), GetItemExternalId(channel), cancellationToken).ConfigureAwait(false); - - if (response != null) - { - imageResponse.HasImage = true; - imageResponse.Stream = response.Stream; - imageResponse.Format = response.Format; - } - } - } - catch (NotImplementedException) - { - } - } - - return imageResponse; - } - - public string Name - { - get { return "Live TV Service Provider"; } - } - - public bool Supports(IHasImages item) - { - return item is LiveTvProgram; - } - - public int Order - { - get - { - // Let the better providers run first - return 100; - } - } - - public bool HasChanged(IHasMetadata item, IDirectoryService directoryService) - { - var liveTvItem = item as LiveTvProgram; - - if (liveTvItem != null) - { - return !liveTvItem.HasImage(ImageType.Primary); - } - return false; - } - } -} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 12b7901f9..8bf7a052e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts }, RequiresOpening = true, RequiresClosing = true, - RequiresLooping = true, + RequiresLooping = info.EnableStreamLooping, ReadAtNativeFramerate = false, diff --git a/Emby.Server.Implementations/Migrations/GuideMigration.cs b/Emby.Server.Implementations/Migrations/GuideMigration.cs deleted file mode 100644 index 78fb6c222..000000000 --- a/Emby.Server.Implementations/Migrations/GuideMigration.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Tasks; -using MediaBrowser.Model.Updates; -using System.Linq; - -namespace Emby.Server.Implementations.Migrations -{ - public class GuideMigration : IVersionMigration - { - private readonly IServerConfigurationManager _config; - private readonly ITaskManager _taskManager; - - public GuideMigration(IServerConfigurationManager config, ITaskManager taskManager) - { - _config = config; - _taskManager = taskManager; - } - - public Task Run() - { - var name = "GuideRefresh3"; - - if (!_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase)) - { - Task.Run(() => - { - _taskManager.QueueScheduledTask(_taskManager.ScheduledTasks.Select(i => i.ScheduledTask) - .First(i => string.Equals(i.Key, "RefreshGuide", StringComparison.OrdinalIgnoreCase))); - }); - - var list = _config.Configuration.Migrations.ToList(); - list.Add(name); - _config.Configuration.Migrations = list.ToArray(); - _config.SaveConfiguration(); - } - - return Task.FromResult(true); - } - } -} diff --git a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs b/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs deleted file mode 100644 index 9d7f67a4f..000000000 --- a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Tasks; -using MediaBrowser.Model.Updates; -using System.Linq; - -namespace Emby.Server.Implementations.Migrations -{ - public class LibraryScanMigration : IVersionMigration - { - private readonly IServerConfigurationManager _config; - private readonly ITaskManager _taskManager; - - public LibraryScanMigration(IServerConfigurationManager config, ITaskManager taskManager) - { - _config = config; - _taskManager = taskManager; - } - - public Task Run() - { - var name = "LibraryScan6"; - - if (!_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase)) - { - Task.Run(() => - { - _taskManager.QueueScheduledTask(_taskManager.ScheduledTasks.Select(i => i.ScheduledTask) - .First(i => string.Equals(i.Key, "RefreshLibrary", StringComparison.OrdinalIgnoreCase))); - }); - - var list = _config.Configuration.Migrations.ToList(); - list.Add(name); - _config.Configuration.Migrations = list.ToArray(); - _config.SaveConfiguration(); - } - - return Task.FromResult(true); - } - } -} diff --git a/Emby.Server.Implementations/News/NewsEntryPoint.cs b/Emby.Server.Implementations/News/NewsEntryPoint.cs index 53c862d47..3c9a3bbf1 100644 --- a/Emby.Server.Implementations/News/NewsEntryPoint.cs +++ b/Emby.Server.Implementations/News/NewsEntryPoint.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Model.Threading; @@ -82,7 +83,7 @@ namespace Emby.Server.Implementations.News var requestOptions = new HttpRequestOptions { Url = "http://emby.media/community/index.php?/blog/rss/1-media-browser-developers-blog", - Progress = new Progress<double>(), + Progress = new SimpleProgress<double>(), UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36", BufferContent = false }; diff --git a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs index 8b3367217..0239ee336 100644 --- a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs +++ b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.Notifications public void Run() { _notificationsRepo.NotificationAdded += _notificationsRepo_NotificationAdded; - _notificationsRepo.NotificationsMarkedRead += _notificationsRepo_NotificationsMarkedRead; } diff --git a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs index 0744fc0d9..17f9b491d 100644 --- a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs +++ b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs @@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.Photos return items; } - protected string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) { return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); } diff --git a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs index e619b6864..9f887ba03 100644 --- a/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.ScheduledTasks @@ -77,7 +78,7 @@ namespace Emby.Server.Implementations.ScheduledTasks try { - await _installationManager.InstallPackage(i, true, new Progress<double>(), cancellationToken).ConfigureAwait(false); + await _installationManager.InstallPackage(i, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs b/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs deleted file mode 100644 index 9bf6f2824..000000000 --- a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs +++ /dev/null @@ -1,105 +0,0 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; - -namespace Emby.Server.Implementations.ScheduledTasks -{ - /// <summary> - /// Class RefreshIntrosTask - /// </summary> - public class RefreshIntrosTask : ILibraryPostScanTask - { - /// <summary> - /// The _library manager - /// </summary> - private readonly ILibraryManager _libraryManager; - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - private readonly IFileSystem _fileSystem; - - /// <summary> - /// Initializes a new instance of the <see cref="RefreshIntrosTask" /> class. - /// </summary> - /// <param name="libraryManager">The library manager.</param> - /// <param name="logger">The logger.</param> - /// <param name="fileSystem">The file system.</param> - public RefreshIntrosTask(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem) - { - _libraryManager = libraryManager; - _logger = logger; - _fileSystem = fileSystem; - } - - /// <summary> - /// Runs the specified progress. - /// </summary> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - var files = _libraryManager.GetAllIntroFiles().ToList(); - - var numComplete = 0; - - foreach (var file in files) - { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - await RefreshIntro(file, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error refreshing intro {0}", ex, file); - } - - numComplete++; - double percent = numComplete; - percent /= files.Count; - progress.Report(percent * 100); - } - } - - /// <summary> - /// Refreshes the intro. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - private async Task RefreshIntro(string path, CancellationToken cancellationToken) - { - var item = _libraryManager.ResolvePath(_fileSystem.GetFileSystemInfo(path)); - - if (item == null) - { - _logger.Error("Intro resolver returned null for {0}", path); - return; - } - - var dbItem = _libraryManager.GetItemById(item.Id); - - if (dbItem != null) - { - item = dbItem; - } - - // Force the save if it's a new item - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs index 28fd8b68c..a41e21a4b 100644 --- a/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/SystemUpdateTask.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.ScheduledTasks @@ -70,7 +71,7 @@ namespace Emby.Server.Implementations.ScheduledTasks EventHandler<double> innerProgressHandler = (sender, e) => progress.Report(e * .1); // Create a progress object for the update check - var innerProgress = new Progress<double>(); + var innerProgress = new SimpleProgress<double>(); innerProgress.ProgressChanged += innerProgressHandler; var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false); @@ -97,7 +98,7 @@ namespace Emby.Server.Implementations.ScheduledTasks innerProgressHandler = (sender, e) => progress.Report(e * .9 + .1); - innerProgress = new Progress<double>(); + innerProgress = new SimpleProgress<double>(); innerProgress.ProgressChanged += innerProgressHandler; await _appHost.UpdateApplication(updateInfo.Package, cancellationToken, innerProgress).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs index e4392d7e6..4d5192fea 100644 --- a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.ServerManager return; } - var charset = _textEncoding.GetDetectedEncodingName(bytes, null); + var charset = _textEncoding.GetDetectedEncodingName(bytes, null, false); if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase)) { diff --git a/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs index 92fa6c424..dbac76bb4 100644 --- a/Emby.Server.Implementations/Session/HttpSessionController.cs +++ b/Emby.Server.Implementations/Session/HttpSessionController.cs @@ -159,24 +159,25 @@ namespace Emby.Server.Implementations.Session public Task SendMessage<T>(string name, T data, CancellationToken cancellationToken) { - var url = PostUrl + "/" + name; - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = false - }; - - options.RequestContent = _json.SerializeToString(data); - options.RequestContentType = "application/json"; - - return _httpClient.Post(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = false - }); + return Task.FromResult(true); + //var url = PostUrl + "/" + name; + + //var options = new HttpRequestOptions + //{ + // Url = url, + // CancellationToken = cancellationToken, + // BufferContent = false + //}; + + //options.RequestContent = _json.SerializeToString(data); + //options.RequestContentType = "application/json"; + + //return _httpClient.Post(new HttpRequestOptions + //{ + // Url = url, + // CancellationToken = cancellationToken, + // BufferContent = false + //}); } private string ToQueryString(Dictionary<string, string> nvc) diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index a5582ddc5..68ab25947 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1622,6 +1622,8 @@ namespace Emby.Server.Implementations.Session TranscodingInfo = session.NowPlayingItem == null ? null : session.TranscodingInfo }; + dto.ServerId = _appHost.SystemId; + if (session.UserId.HasValue) { dto.UserId = session.UserId.Value.ToString("N"); @@ -1671,7 +1673,6 @@ namespace Emby.Server.Implementations.Session dtoOptions.Fields.Remove(ItemFields.DisplayPreferencesId); dtoOptions.Fields.Remove(ItemFields.Etag); dtoOptions.Fields.Remove(ItemFields.ExternalEtag); - dtoOptions.Fields.Remove(ItemFields.IndexOptions); dtoOptions.Fields.Remove(ItemFields.InheritedParentalRatingValue); dtoOptions.Fields.Remove(ItemFields.ItemCounts); dtoOptions.Fields.Remove(ItemFields.Keywords); diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index eed17fb66..717416da1 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -246,7 +246,7 @@ namespace Emby.Server.Implementations.Updates { Url = "https://www.mb3admin.com/admin/service/MB3Packages.json", CancellationToken = cancellationToken, - Progress = new Progress<Double>() + Progress = new SimpleProgress<Double>() }).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config index 5ce754d3f..468bf925f 100644 --- a/Emby.Server.Implementations/packages.config +++ b/Emby.Server.Implementations/packages.config @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Emby.XmlTv" version="1.0.8" targetFramework="portable45-net45+win8" /> + <package id="Emby.XmlTv" version="1.0.9" targetFramework="net46" /> <package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" /> <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" /> - <package id="SQLitePCLRaw.core" version="1.1.5" targetFramework="portable45-net45+win8" /> + <package id="SQLitePCLRaw.core" version="1.1.6" targetFramework="net46" /> </packages>
\ No newline at end of file |
