diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
index 3dbe7239dd..9820829ae6 100644
--- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
@@ -53,7 +53,11 @@ namespace Emby.Drawing.ImageMagick
"arw",
"webp",
"gif",
- "bmp"
+ "bmp",
+ "erf",
+ "raf",
+ "rw2",
+ "nrw"
};
}
}
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 80ebbb7190..e9f8f81f31 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -829,18 +829,7 @@ namespace Emby.Drawing
// Run the enhancers sequentially in order of priority
foreach (var enhancer in imageEnhancers)
{
- var typeName = enhancer.GetType().Name;
-
- try
- {
- await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("{0} failed enhancing {1}", ex, typeName, item.Name);
-
- throw;
- }
+ await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
// Feed the output into the next enhancer as input
inputPath = outputPath;
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 7c5f7cde40..c6e45c61ab 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -15,6 +16,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
{
@@ -43,7 +45,13 @@ namespace MediaBrowser.Api
private readonly IFileSystem _fileSystem;
private readonly IMediaSourceManager _mediaSourceManager;
- public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1);
+ ///
+ /// The active transcoding jobs
+ ///
+ private readonly List _activeTranscodingJobs = new List();
+
+ private readonly Dictionary _transcodingLocks =
+ new Dictionary();
///
/// Initializes a new instance of the class.
@@ -66,6 +74,21 @@ namespace MediaBrowser.Api
_sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
}
+ public SemaphoreSlim GetTranscodingLock(string outputPath)
+ {
+ lock (_transcodingLocks)
+ {
+ SemaphoreSlim result;
+ if (!_transcodingLocks.TryGetValue(outputPath, out result))
+ {
+ result = new SemaphoreSlim(1, 1);
+ _transcodingLocks[outputPath] = result;
+ }
+
+ return result;
+ }
+ }
+
private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
@@ -147,11 +170,6 @@ namespace MediaBrowser.Api
}
}
- ///
- /// The active transcoding jobs
- ///
- private readonly List _activeTranscodingJobs = new List();
-
///
/// Called when [transcode beginning].
///
@@ -187,7 +205,8 @@ namespace MediaBrowser.Api
CancellationTokenSource = cancellationTokenSource,
Id = transcodingJobId,
PlaySessionId = playSessionId,
- LiveStreamId = liveStreamId
+ LiveStreamId = liveStreamId,
+ MediaSource = state.MediaSource
};
_activeTranscodingJobs.Add(job);
@@ -256,6 +275,11 @@ namespace MediaBrowser.Api
}
}
+ lock (_transcodingLocks)
+ {
+ _transcodingLocks.Remove(path);
+ }
+
if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
{
_sessionManager.ClearTranscodingInfo(state.Request.DeviceId);
@@ -281,6 +305,14 @@ namespace MediaBrowser.Api
}
}
+ public TranscodingJob GetTranscodingJob(string playSessionId)
+ {
+ lock (_activeTranscodingJobs)
+ {
+ return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
///
/// Called when [transcode begin request].
///
@@ -487,6 +519,11 @@ namespace MediaBrowser.Api
}
}
+ lock (_transcodingLocks)
+ {
+ _transcodingLocks.Remove(job.Path);
+ }
+
lock (job.ProcessLock)
{
if (job.TranscodingThrottler != null)
@@ -530,7 +567,7 @@ namespace MediaBrowser.Api
{
try
{
- await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -656,6 +693,7 @@ namespace MediaBrowser.Api
/// Gets or sets the path.
///
/// The path.
+ public MediaSourceInfo MediaSource { get; set; }
public string Path { get; set; }
///
/// Gets or sets the type.
@@ -751,12 +789,12 @@ namespace MediaBrowser.Api
{
if (KillTimer == null)
{
- Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite);
}
else
{
- Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite);
}
}
@@ -775,7 +813,7 @@ namespace MediaBrowser.Api
{
var intervalMs = PingTimeout;
- Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite);
}
}
diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs
index 4bcd33d9e3..494a6e756c 100644
--- a/MediaBrowser.Api/ConnectService.cs
+++ b/MediaBrowser.Api/ConnectService.cs
@@ -7,6 +7,7 @@ using ServiceStack;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Session;
namespace MediaBrowser.Api
{
@@ -76,12 +77,12 @@ namespace MediaBrowser.Api
public class ConnectService : BaseApiService
{
private readonly IConnectManager _connectManager;
- private readonly IUserManager _userManager;
+ private readonly ISessionManager _sessionManager;
- public ConnectService(IConnectManager connectManager, IUserManager userManager)
+ public ConnectService(IConnectManager connectManager, ISessionManager sessionManager)
{
_connectManager = connectManager;
- _userManager = userManager;
+ _sessionManager = sessionManager;
}
public object Post(CreateConnectLink request)
@@ -141,10 +142,33 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException();
}
+ var auth = AuthorizationContext.GetAuthorizationInfo(Request);
+
+ if (string.IsNullOrWhiteSpace(auth.Client))
+ {
+ return ToOptimizedResult(new ConnectAuthenticationExchangeResult
+ {
+ AccessToken = user.ConnectAccessKey,
+ LocalUserId = user.Id.ToString("N")
+ });
+ }
+
+ var session = await _sessionManager.CreateNewSession(new AuthenticationRequest
+ {
+ App = auth.Client,
+ AppVersion = auth.Version,
+ DeviceId = auth.DeviceId,
+ DeviceName = auth.Device,
+ RemoteEndPoint = Request.RemoteIp,
+ Username = user.Name,
+ UserId = user.Id.ToString("N")
+
+ }).ConfigureAwait(false);
+
return ToOptimizedResult(new ConnectAuthenticationExchangeResult
{
- AccessToken = user.ConnectAccessKey,
- LocalUserId = user.Id.ToString("N")
+ AccessToken = session.AccessToken,
+ LocalUserId = session.User.Id
});
}
}
diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs
index 4e7b1a7d58..b2c7e5532a 100644
--- a/MediaBrowser.Api/Dlna/DlnaServerService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs
@@ -7,6 +7,8 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
namespace MediaBrowser.Api.Dlna
{
@@ -109,13 +111,15 @@ namespace MediaBrowser.Api.Dlna
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
private const string XMLContentType = "text/xml; charset=UTF-8";
+ private readonly IMemoryStreamProvider _memoryStreamProvider;
- public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar)
+ public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar, IMemoryStreamProvider memoryStreamProvider)
{
_dlnaManager = dlnaManager;
_contentDirectory = contentDirectory;
_connectionManager = connectionManager;
_mediaReceiverRegistrar = mediaReceiverRegistrar;
+ _memoryStreamProvider = memoryStreamProvider;
}
public object Get(GetDescriptionXml request)
@@ -201,7 +205,7 @@ namespace MediaBrowser.Api.Dlna
{
using (var response = _dlnaManager.GetIcon(request.Filename))
{
- using (var ms = new MemoryStream())
+ using (var ms = _memoryStreamProvider.CreateNew())
{
response.Stream.CopyTo(ms);
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index b3b75359aa..57aa5575f7 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -104,7 +105,13 @@ namespace MediaBrowser.Api
MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(),
Recursive = true,
- EnableTotalRecordCount = false
+ EnableTotalRecordCount = false,
+ DtoOptions = new Controller.Dto.DtoOptions
+ {
+ Fields = new List { ItemFields.Genres, ItemFields.Tags },
+ EnableImages = false,
+ EnableUserData = false
+ }
};
return query;
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index 0953b95e62..efa69d3336 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -200,6 +200,8 @@ namespace MediaBrowser.Api
(!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder :
_libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
+ var dtoOptions = GetDtoOptions(request);
+
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = request.Limit,
@@ -207,12 +209,11 @@ namespace MediaBrowser.Api
{
typeof(Game).Name
},
- SimilarTo = item
+ SimilarTo = item,
+ DtoOptions = dtoOptions
}).ToList();
- var dtoOptions = GetDtoOptions(request);
-
var result = new QueryResult
{
Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
index b21e544951..25d7639c64 100644
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ b/MediaBrowser.Api/Images/RemoteImageService.cs
@@ -273,7 +273,8 @@ namespace MediaBrowser.Api.Images
{
var result = await _httpClient.GetResponse(new HttpRequestOptions
{
- Url = url
+ Url = url,
+ BufferContent = false
}).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 2778cfe29c..687a21a468 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -70,12 +70,13 @@ namespace MediaBrowser.Api
Cultures = _localizationManager.GetCultures().ToList()
};
- if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName))
+ if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
+ item.SourceType == SourceType.Library)
{
var inheritedContentType = _libraryManager.GetInheritedContentType(item);
var configuredContentType = _libraryManager.GetConfiguredContentType(item);
- if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(configuredContentType))
+ if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
{
info.ContentTypeOptions = GetContentTypeOptions(true);
info.ContentType = configuredContentType;
@@ -242,11 +243,7 @@ namespace MediaBrowser.Api
hasBudget.Revenue = request.Revenue;
}
- var hasOriginalTitle = item as IHasOriginalTitle;
- if (hasOriginalTitle != null)
- {
- hasOriginalTitle.OriginalTitle = hasOriginalTitle.OriginalTitle;
- }
+ item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
@@ -277,10 +274,9 @@ namespace MediaBrowser.Api
item.Tags = request.Tags;
- var hasTaglines = item as IHasTaglines;
- if (hasTaglines != null)
+ if (request.Taglines != null)
{
- hasTaglines.Taglines = request.Taglines;
+ item.Tagline = request.Taglines.FirstOrDefault();
}
var hasShortOverview = item as IHasShortOverview;
@@ -307,8 +303,6 @@ namespace MediaBrowser.Api
item.OfficialRating = string.IsNullOrWhiteSpace(request.OfficialRating) ? null : request.OfficialRating;
item.CustomRating = request.CustomRating;
- SetProductionLocations(item, request);
-
item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
@@ -416,23 +410,5 @@ namespace MediaBrowser.Api
series.AirTime = request.AirTime;
}
}
-
- private void SetProductionLocations(BaseItem item, BaseItemDto request)
- {
- var hasProductionLocations = item as IHasProductionLocations;
-
- if (hasProductionLocations != null)
- {
- hasProductionLocations.ProductionLocations = request.ProductionLocations;
- }
-
- var person = item as Person;
- if (person != null)
- {
- person.PlaceOfBirth = request.ProductionLocations == null
- ? null
- : request.ProductionLocations.FirstOrDefault();
- }
- }
}
}
diff --git a/MediaBrowser.Api/Library/ChapterService.cs b/MediaBrowser.Api/Library/ChapterService.cs
deleted file mode 100644
index 6b8dd18f10..0000000000
--- a/MediaBrowser.Api/Library/ChapterService.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using MediaBrowser.Controller.Chapters;
-using MediaBrowser.Controller.Net;
-using ServiceStack;
-using System.Linq;
-
-namespace MediaBrowser.Api.Library
-{
- [Route("/Providers/Chapters", "GET")]
- public class GetChapterProviders : IReturnVoid
- {
- }
-
- [Authenticated]
- public class ChapterService : BaseApiService
- {
- private readonly IChapterManager _chapterManager;
-
- public ChapterService(IChapterManager chapterManager)
- {
- _chapterManager = chapterManager;
- }
-
- public object Get(GetChapterProviders request)
- {
- var result = _chapterManager.GetProviders().ToList();
-
- return ToOptimizedResult(result);
- }
- }
-}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 14a771db03..e0dfcb9ad2 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -25,6 +25,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Controller.Configuration;
namespace MediaBrowser.Api.Library
{
@@ -288,12 +289,13 @@ namespace MediaBrowser.Api.Library
private readonly ITVSeriesManager _tvManager;
private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem;
+ private readonly IServerConfigurationManager _config;
///
/// Initializes a new instance of the class.
///
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
- IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
+ IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, IServerConfigurationManager config)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
@@ -307,6 +309,7 @@ namespace MediaBrowser.Api.Library
_tvManager = tvManager;
_libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
+ _config = config;
}
public object Get(GetSimilarItems request)
@@ -377,7 +380,7 @@ namespace MediaBrowser.Api.Library
if (item is Movie || (program != null && program.IsMovie) || item is Trailer)
{
- return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService)
+ return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _config)
{
AuthorizationContext = AuthorizationContext,
Logger = Logger,
@@ -832,14 +835,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
- while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
+ while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
var dtoOptions = GetDtoOptions(request);
- var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
+ var dtos = item.ThemeSongIds.Select(_libraryManager.GetItemById)
.Where(i => i != null)
.OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@@ -876,14 +879,14 @@ namespace MediaBrowser.Api.Library
: (Folder)_libraryManager.RootFolder)
: _libraryManager.GetItemById(request.Id);
- while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.GetParent() != null)
+ while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
var dtoOptions = GetDtoOptions(request);
- var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
+ var dtos = item.ThemeVideoIds.Select(_libraryManager.GetItemById)
.Where(i => i != null)
.OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
@@ -898,30 +901,6 @@ namespace MediaBrowser.Api.Library
};
}
- private List GetThemeVideoIds(BaseItem item)
- {
- var i = item as IHasThemeMedia;
-
- if (i != null)
- {
- return i.ThemeVideoIds;
- }
-
- return new List();
- }
-
- private List GetThemeSongIds(BaseItem item)
- {
- var i = item as IHasThemeMedia;
-
- if (i != null)
- {
- return i.ThemeSongIds;
- }
-
- return new List();
- }
-
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public object Get(GetYearIndex request)
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index 72966a7cdc..e872061a74 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -112,6 +112,8 @@ namespace MediaBrowser.Api.Library
/// The name.
public string Path { get; set; }
+ public MediaPathInfo PathInfo { get; set; }
+
///
/// Gets or sets a value indicating whether [refresh library].
///
@@ -119,6 +121,18 @@ namespace MediaBrowser.Api.Library
public bool RefreshLibrary { get; set; }
}
+ [Route("/Library/VirtualFolders/Paths/Update", "POST")]
+ public class UpdateMediaPath : IReturnVoid
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ public string Name { get; set; }
+
+ public MediaPathInfo PathInfo { get; set; }
+ }
+
[Route("/Library/VirtualFolders/Paths", "DELETE")]
public class RemoveMediaPath : IReturnVoid
{
@@ -212,7 +226,12 @@ namespace MediaBrowser.Api.Library
{
var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
- _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, libraryOptions, request.RefreshLibrary);
+ if (request.Paths != null && request.Paths.Length > 0)
+ {
+ libraryOptions.PathInfos = request.Paths.Select(i => new MediaPathInfo { Path = i }).ToArray();
+ }
+
+ _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, libraryOptions, request.RefreshLibrary);
}
///
@@ -308,7 +327,16 @@ namespace MediaBrowser.Api.Library
try
{
- _libraryManager.AddMediaPath(request.Name, request.Path);
+ var mediaPath = request.PathInfo;
+
+ if (mediaPath == null)
+ {
+ mediaPath = new MediaPathInfo
+ {
+ Path = request.Path
+ };
+ }
+ _libraryManager.AddMediaPath(request.Name, mediaPath);
}
finally
{
@@ -332,6 +360,20 @@ namespace MediaBrowser.Api.Library
}
}
+ ///
+ /// Posts the specified request.
+ ///
+ /// The request.
+ public void Post(UpdateMediaPath request)
+ {
+ if (string.IsNullOrWhiteSpace(request.Name))
+ {
+ throw new ArgumentNullException("request");
+ }
+
+ _libraryManager.UpdateMediaPath(request.Name, request.PathInfo);
+ }
+
///
/// Deletes the specified request.
///
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 545ac162ff..4217cd6abe 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -12,9 +12,14 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Api.Playback.Progressive;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
namespace MediaBrowser.Api.LiveTv
{
@@ -44,6 +49,21 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get; set; }
+ [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsMovie { get; set; }
+
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
+
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
+ [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsKids { get; set; }
+
+ [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSports { get; set; }
+
///
/// The maximum number of items to return
///
@@ -85,6 +105,26 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
+ public string SortBy { get; set; }
+
+ public SortOrder? SortOrder { get; set; }
+
+ ///
+ /// Gets the order by.
+ ///
+ /// IEnumerable{ItemSortBy}.
+ public string[] GetOrderBy()
+ {
+ var val = SortBy;
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return new string[] { };
+ }
+
+ return val.Split(',');
+ }
+
public GetChannels()
{
AddCurrentProgram = true;
@@ -155,12 +195,73 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
+ public bool? IsMovie { get; set; }
+ public bool? IsSeries { get; set; }
+ public bool? IsKids { get; set; }
+ public bool? IsSports { get; set; }
+ public bool? IsNews { get; set; }
+
public GetRecordings()
{
EnableTotalRecordCount = true;
}
}
+ [Route("/LiveTv/Recordings/Series", "GET", Summary = "Gets live tv recordings")]
+ [Authenticated]
+ public class GetRecordingSeries : IReturn>, IHasDtoOptions
+ {
+ [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ChannelId { get; set; }
+
+ [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string UserId { get; set; }
+
+ [ApiMember(Name = "GroupId", Description = "Optional filter by recording group.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string GroupId { get; set; }
+
+ [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? StartIndex { get; set; }
+
+ [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? Limit { get; set; }
+
+ [ApiMember(Name = "Status", Description = "Optional filter by recording status.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public RecordingStatus? Status { get; set; }
+
+ [ApiMember(Name = "Status", Description = "Optional filter by recordings that are in progress, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ public bool? IsInProgress { get; set; }
+
+ [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string SeriesTimerId { get; set; }
+
+ [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableImages { get; set; }
+
+ [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? ImageTypeLimit { get; set; }
+
+ [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string EnableImageTypes { get; set; }
+
+ ///
+ /// Fields to return within the items, in addition to basic information
+ ///
+ /// The fields.
+ [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string Fields { get; set; }
+
+ public bool EnableTotalRecordCount { get; set; }
+
+ [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+ public bool? EnableUserData { get; set; }
+
+ public GetRecordingSeries()
+ {
+ EnableTotalRecordCount = true;
+ }
+ }
+
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
[Authenticated]
public class GetRecordingGroups : IReturn>
@@ -215,6 +316,8 @@ namespace MediaBrowser.Api.LiveTv
public string SeriesTimerId { get; set; }
public bool? IsActive { get; set; }
+
+ public bool? IsScheduled { get; set; }
}
[Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
@@ -245,6 +348,12 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; }
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
+
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; }
@@ -280,6 +389,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
+ public string SeriesTimerId { get; set; }
+
///
/// Fields to return within the items, in addition to basic information
///
@@ -316,15 +427,21 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? HasAired { get; set; }
- [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
- public bool? IsSports { get; set; }
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
- [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; }
- [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
+ [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; }
+ [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSports { get; set; }
+
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; }
@@ -535,12 +652,6 @@ namespace MediaBrowser.Api.LiveTv
[Authenticated]
public class GetLiveTvRegistrationInfo : IReturn
{
- [ApiMember(Name = "ChannelId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ChannelId { get; set; }
-
- [ApiMember(Name = "ProgramId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string ProgramId { get; set; }
-
[ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Feature { get; set; }
}
@@ -559,16 +670,30 @@ namespace MediaBrowser.Api.LiveTv
}
+ [Route("/LiveTv/LiveStreamFiles/{Id}/stream.{Container}", "GET", Summary = "Gets a live tv channel")]
+ public class GetLiveStreamFile
+ {
+ public string Id { get; set; }
+ public string Container { get; set; }
+ }
+
+ [Route("/LiveTv/LiveRecordings/{Id}/stream", "GET", Summary = "Gets a live tv channel")]
+ public class GetLiveRecordingFile
+ {
+ public string Id { get; set; }
+ }
+
public class LiveTvService : BaseApiService
{
private readonly ILiveTvManager _liveTvManager;
private readonly IUserManager _userManager;
- private readonly IConfigurationManager _config;
+ private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly ILibraryManager _libraryManager;
private readonly IDtoService _dtoService;
+ private readonly IFileSystem _fileSystem;
- public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService)
+ public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem)
{
_liveTvManager = liveTvManager;
_userManager = userManager;
@@ -576,6 +701,41 @@ namespace MediaBrowser.Api.LiveTv
_httpClient = httpClient;
_libraryManager = libraryManager;
_dtoService = dtoService;
+ _fileSystem = fileSystem;
+ }
+
+ public async Task
/// The metadata path.
public string MetadataPath { get; set; }
+ public string MetadataNetworkPath { get; set; }
public string LastVersion { get; set; }
@@ -167,6 +168,8 @@ namespace MediaBrowser.Model.Configuration
public MetadataOptions[] MetadataOptions { get; set; }
public bool EnableAutomaticRestart { get; set; }
+ public bool SkipDeserializationForBasicTypes { get; set; }
+ public bool SkipDeserializationForPrograms { get; set; }
public PathSubstitution[] PathSubstitutions { get; set; }
@@ -176,7 +179,6 @@ namespace MediaBrowser.Model.Configuration
public string UICulture { get; set; }
public PeopleMetadataOptions PeopleMetadataOptions { get; set; }
- public bool FindInternetTrailers { get; set; }
public bool SaveMetadataHidden { get; set; }
@@ -184,8 +186,6 @@ namespace MediaBrowser.Model.Configuration
public int RemoteClientBitrateLimit { get; set; }
- public AutoOnOff EnableLibraryMonitor { get; set; }
-
public int SharingExpirationDays { get; set; }
public string[] Migrations { get; set; }
@@ -194,8 +194,6 @@ namespace MediaBrowser.Model.Configuration
public int SchemaVersion { get; set; }
public int SqliteCacheSize { get; set; }
- public bool DownloadImagesInAdvance { get; set; }
-
public bool EnableAnonymousUsageReporting { get; set; }
public bool EnableStandaloneMusicKeys { get; set; }
public bool EnableLocalizedGuids { get; set; }
@@ -205,7 +203,11 @@ namespace MediaBrowser.Model.Configuration
public bool DisplayCollectionsView { get; set; }
public string[] LocalNetworkAddresses { get; set; }
public string[] CodecsUsed { get; set; }
+ public bool EnableChannelView { get; set; }
+ public bool EnableExternalContentInSuggestions { get; set; }
+ public bool EnableSimpleArtistDetection { get; set; }
+ public int ImageExtractionTimeoutMs { get; set; }
///
/// Initializes a new instance of the class.
///
@@ -215,9 +217,11 @@ namespace MediaBrowser.Model.Configuration
Migrations = new string[] { };
CodecsUsed = new string[] { };
SqliteCacheSize = 0;
+ ImageExtractionTimeoutMs = 0;
EnableLocalizedGuids = true;
DisplaySpecialsWithinSeasons = true;
+ EnableExternalContentInSuggestions = true;
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
@@ -230,6 +234,7 @@ namespace MediaBrowser.Model.Configuration
EnableAnonymousUsageReporting = true;
EnableAutomaticRestart = true;
+ EnableFolderView = true;
EnableUPnP = true;
SharingExpirationDays = 30;
@@ -239,11 +244,9 @@ namespace MediaBrowser.Model.Configuration
// 5 minutes
MinResumeDurationSeconds = 300;
- EnableLibraryMonitor = AutoOnOff.Auto;
LibraryMonitorDelay = 60;
EnableInternetProviders = true;
- FindInternetTrailers = true;
PathSubstitutions = new PathSubstitution[] { };
ContentTypes = new NameValuePair[] { };
@@ -432,7 +435,8 @@ namespace MediaBrowser.Model.Configuration
Limit = 0,
Type = ImageType.Disc
}
- }
+ },
+ DisabledMetadataFetchers = new []{ "TheAudioDB" }
},
new MetadataOptions(1, 1280)
@@ -470,7 +474,8 @@ namespace MediaBrowser.Model.Configuration
Limit = 0,
Type = ImageType.Logo
}
- }
+ },
+ DisabledMetadataFetchers = new []{ "TheAudioDB" }
},
new MetadataOptions(1, 1280)
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 313c5243c3..a6785a06a7 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -41,7 +41,6 @@ namespace MediaBrowser.Model.Configuration
public string[] PlainFolderViews { get; set; }
public bool HidePlayedInLatest { get; set; }
- public bool EnableChannelView { get; set; }
public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; }
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index 69f1369dc0..ec13cacfae 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -20,12 +20,15 @@ namespace MediaBrowser.Model.Dlna
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
- string videoCodecTag)
+ string videoCodecTag,
+ bool? isAvc)
{
switch (condition.Property)
{
case ProfileConditionValue.IsAnamorphic:
return IsConditionSatisfied(condition, isAnamorphic);
+ case ProfileConditionValue.IsAvc:
+ return IsConditionSatisfied(condition, isAvc);
case ProfileConditionValue.VideoFramerate:
return IsConditionSatisfied(condition, videoFramerate);
case ProfileConditionValue.VideoLevel:
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index c4b3383a2b..4a16a27805 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -118,7 +118,8 @@ namespace MediaBrowser.Model.Dlna
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
- string videoCodecTag)
+ string videoCodecTag,
+ bool? isAvc)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
@@ -159,7 +160,8 @@ namespace MediaBrowser.Model.Dlna
refFrames,
numVideoStreams,
numAudioStreams,
- videoCodecTag);
+ videoCodecTag,
+ isAvc);
List orgPnValues = new List();
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index d6a3223227..884a9f29d1 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -285,7 +285,8 @@ namespace MediaBrowser.Model.Dlna
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
- string videoCodecTag)
+ string videoCodecTag,
+ bool? isAvc)
{
container = StringHelper.TrimStart(container ?? string.Empty, '.');
@@ -319,7 +320,7 @@ namespace MediaBrowser.Model.Dlna
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
+ if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
anyOff = true;
break;
diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
index c17a09c3fb..7e2002f179 100644
--- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
+++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
@@ -20,6 +20,7 @@
NumAudioStreams = 16,
NumVideoStreams = 17,
IsSecondaryAudio = 18,
- VideoCodecTag = 19
+ VideoCodecTag = 19,
+ IsAvc = 20
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 13d5597738..52b7fd43a3 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -541,6 +541,7 @@ namespace MediaBrowser.Model.Dlna
float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
+ bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : item.Timestamp;
int? packetLength = videoStream == null ? null : videoStream.PacketLength;
@@ -549,7 +550,7 @@ namespace MediaBrowser.Model.Dlna
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
+ if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item);
applyConditions = false;
@@ -602,33 +603,20 @@ namespace MediaBrowser.Model.Dlna
private int GetAudioBitrate(string subProtocol, int? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream)
{
- var defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? 192000;
+ int defaultBitrate = audioStream == null ? 192000 : audioStream.BitRate ?? 192000;
// Reduce the bitrate if we're downmixing
if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
{
defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
}
- if (targetAudioChannels.HasValue)
+ if (StringHelper.EqualsIgnoreCase(subProtocol, "hls"))
{
- if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1200000)
- {
- if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3"))
- {
- if (string.Equals(subProtocol, "hls", StringComparison.OrdinalIgnoreCase))
- {
- defaultBitrate = Math.Max(384000, defaultBitrate);
- }
- else
- {
- defaultBitrate = Math.Max(448000, defaultBitrate);
- }
- }
- else
- {
- defaultBitrate = Math.Max(320000, defaultBitrate);
- }
- }
+ defaultBitrate = Math.Min(384000, defaultBitrate);
+ }
+ else
+ {
+ defaultBitrate = Math.Min(448000, defaultBitrate);
}
int encoderAudioBitrateLimit = int.MaxValue;
@@ -647,6 +635,14 @@ namespace MediaBrowser.Model.Dlna
}
}
+ if (maxTotalBitrate.HasValue)
+ {
+ if (maxTotalBitrate.Value < 640000)
+ {
+ defaultBitrate = Math.Min(128000, defaultBitrate);
+ }
+ }
+
return Math.Min(defaultBitrate, encoderAudioBitrateLimit);
}
@@ -723,6 +719,7 @@ namespace MediaBrowser.Model.Dlna
float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
+ bool? isAvc = videoStream == null ? null : videoStream.IsAVC;
int? audioBitrate = audioStream == null ? null : audioStream.BitRate;
int? audioChannels = audioStream == null ? null : audioStream.Channels;
@@ -738,7 +735,7 @@ namespace MediaBrowser.Model.Dlna
// Check container conditions
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
@@ -765,7 +762,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
+ if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource);
applyConditions = false;
@@ -785,7 +782,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index ac024f00b9..c9cb873e14 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -215,13 +215,26 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
- if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls"))
+ var forceStartPosition = false;
+ long startPositionTicks = item.StartPositionTicks;
+ //if (item.MediaSource.DateLiveStreamOpened.HasValue && startPositionTicks == 0)
+ //{
+ // var elapsed = DateTime.UtcNow - item.MediaSource.DateLiveStreamOpened.Value;
+ // elapsed -= TimeSpan.FromSeconds(20);
+ // if (elapsed.TotalSeconds >= 0)
+ // {
+ // startPositionTicks = elapsed.Ticks + startPositionTicks;
+ // forceStartPosition = true;
+ // }
+ //}
+
+ if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls") && !forceStartPosition)
{
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
}
else
{
- list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(item.StartPositionTicks)));
+ list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(startPositionTicks)));
}
list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty));
@@ -663,6 +676,19 @@ namespace MediaBrowser.Model.Dlna
}
}
+ public bool? IsTargetAVC
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? null : TargetVideoStream.IsAVC;
+ }
+
+ return true;
+ }
+ }
+
public int? TargetWidth
{
get
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 348a781ae1..33aa8bb1c8 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -169,6 +169,8 @@ namespace MediaBrowser.Model.Dto
/// The game system.
public string GameSystem { get; set; }
+ public string[] ProductionLocations { get; set; }
+
///
/// Gets or sets the critic rating summary.
///
@@ -787,11 +789,7 @@ namespace MediaBrowser.Model.Dto
/// The home page URL.
public string HomePageUrl { get; set; }
- ///
- /// Gets or sets the production locations.
- ///
- /// The production locations.
- public List ProductionLocations { get; set; }
+ public string PlaceOfBirth { get; set; }
///
/// Gets or sets the budget.
@@ -826,6 +824,7 @@ namespace MediaBrowser.Model.Dto
///
/// The series count.
public int? SeriesCount { get; set; }
+ public int? ProgramCount { get; set; }
///
/// Gets or sets the episode count.
///
diff --git a/MediaBrowser.Model/Dto/ItemCounts.cs b/MediaBrowser.Model/Dto/ItemCounts.cs
index 66c3dfebc7..8ceb3a86b9 100644
--- a/MediaBrowser.Model/Dto/ItemCounts.cs
+++ b/MediaBrowser.Model/Dto/ItemCounts.cs
@@ -26,6 +26,7 @@
/// The game count.
public int GameCount { get; set; }
public int ArtistCount { get; set; }
+ public int ProgramCount { get; set; }
///
/// Gets or sets the game system count.
///
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index bb07d9cb6f..8149e3ff5e 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Entities;
+using System;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
@@ -26,7 +27,7 @@ namespace MediaBrowser.Model.Dto
public bool SupportsTranscoding { get; set; }
public bool SupportsDirectStream { get; set; }
public bool SupportsDirectPlay { get; set; }
-
+ public bool IsInfiniteStream { get; set; }
public bool RequiresOpening { get; set; }
public string OpenToken { get; set; }
public bool RequiresClosing { get; set; }
@@ -52,7 +53,7 @@ namespace MediaBrowser.Model.Dto
public string TranscodingUrl { get; set; }
public string TranscodingSubProtocol { get; set; }
public string TranscodingContainer { get; set; }
-
+
public MediaSourceInfo()
{
Formats = new List();
diff --git a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
index 4d863c6eb2..7e93a130b6 100644
--- a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
@@ -10,6 +10,8 @@ namespace MediaBrowser.Model.LiveTv
///
public string Id { get; set; }
+ public string Type { get; set; }
+
///
/// Gets or sets the server identifier.
///
@@ -105,5 +107,6 @@ namespace MediaBrowser.Model.LiveTv
///
/// true if this instance is post padding required; otherwise, false.
public bool IsPostPaddingRequired { get; set; }
+ public KeepUntil KeepUntil { get; set; }
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
index 0ece1e4a00..4505b80a02 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
@@ -1,4 +1,5 @@
-
+using MediaBrowser.Model.Entities;
+
namespace MediaBrowser.Model.LiveTv
{
///
@@ -61,9 +62,42 @@ namespace MediaBrowser.Model.LiveTv
public bool AddCurrentProgram { get; set; }
public bool EnableUserData { get; set; }
+ ///
+ /// Used to specific whether to return news or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsNews { get; set; }
+
+ ///
+ /// Used to specific whether to return movies or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsMovie { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is kids.
+ ///
+ /// null if [is kids] contains no value, true if [is kids]; otherwise, false.
+ public bool? IsKids { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance is sports.
+ ///
+ /// null if [is sports] contains no value, true if [is sports]; otherwise, false.
+ public bool? IsSports { get; set; }
+ public bool? IsSeries { get; set; }
+
+ public string[] SortBy { get; set; }
+
+ ///
+ /// The sort order to return results with
+ ///
+ /// The sort order.
+ public SortOrder? SortOrder { get; set; }
+
public LiveTvChannelQuery()
{
EnableUserData = true;
+ SortBy = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 242a2d24e4..a6240afe6d 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -13,6 +13,7 @@ namespace MediaBrowser.Model.LiveTv
public string SeriesRecordingPath { get; set; }
public bool EnableAutoOrganize { get; set; }
public bool EnableRecordingEncoding { get; set; }
+ public string RecordingEncodingFormat { get; set; }
public bool EnableRecordingSubfolders { get; set; }
public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
@@ -31,6 +32,7 @@ namespace MediaBrowser.Model.LiveTv
TunerHosts = new List();
ListingProviders = new List();
MediaLocationsCreated = new string[] { };
+ RecordingEncodingFormat = "mp4";
}
}
@@ -58,7 +60,6 @@ namespace MediaBrowser.Model.LiveTv
public TunerHostInfo()
{
IsEnabled = true;
- AllowHWTranscoding = true;
}
}
diff --git a/MediaBrowser.Model/LiveTv/ProgramAudio.cs b/MediaBrowser.Model/LiveTv/ProgramAudio.cs
index 902079b9ab..9a272492ca 100644
--- a/MediaBrowser.Model/LiveTv/ProgramAudio.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramAudio.cs
@@ -6,6 +6,7 @@
Stereo,
Dolby,
DolbyDigital,
- Thx
+ Thx,
+ Atmos
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index bf459237a0..ad57d14732 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -41,6 +41,7 @@ namespace MediaBrowser.Model.LiveTv
///
/// The user identifier.
public string UserId { get; set; }
+ public string SeriesTimerId { get; set; }
///
/// The earliest date for which a program starts to return
@@ -62,6 +63,12 @@ namespace MediaBrowser.Model.LiveTv
///
public DateTime? MaxEndDate { get; set; }
+ ///
+ /// Used to specific whether to return news or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsNews { get; set; }
+
///
/// Used to specific whether to return movies or not
///
@@ -83,6 +90,7 @@ namespace MediaBrowser.Model.LiveTv
/// Skips over a given number of items within the results. Use for paging.
///
public int? StartIndex { get; set; }
+ public bool? IsSeries { get; set; }
///
/// Gets or sets a value indicating whether this instance has aired.
diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
index 0e6d081a1d..4bc506bf6d 100644
--- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
@@ -45,11 +45,17 @@ namespace MediaBrowser.Model.LiveTv
/// The limit.
public int? Limit { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance is movie.
+ ///
+ /// null if [is movie] contains no value, true if [is movie]; otherwise, false.
+ public bool? IsNews { get; set; }
///
/// Gets or sets a value indicating whether this instance is movie.
///
/// null if [is movie] contains no value, true if [is movie]; otherwise, false.
public bool? IsMovie { get; set; }
+ public bool? IsSeries { get; set; }
///
/// Gets or sets a value indicating whether this instance is kids.
///
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index 923d303f80..265aad3358 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -68,6 +68,11 @@ namespace MediaBrowser.Model.LiveTv
/// The fields.
public ItemFields[] Fields { get; set; }
public bool? EnableImages { get; set; }
+ public bool? IsNews { get; set; }
+ public bool? IsMovie { get; set; }
+ public bool? IsSeries { get; set; }
+ public bool? IsKids { get; set; }
+ public bool? IsSports { get; set; }
public int? ImageTypeLimit { get; set; }
public ImageType[] EnableImageTypes { get; set; }
diff --git a/MediaBrowser.Model/LiveTv/RecordingStatus.cs b/MediaBrowser.Model/LiveTv/RecordingStatus.cs
index 7ab716c4da..571ff9c998 100644
--- a/MediaBrowser.Model/LiveTv/RecordingStatus.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingStatus.cs
@@ -7,7 +7,6 @@ namespace MediaBrowser.Model.LiveTv
Scheduled,
InProgress,
Completed,
- Aborted,
Cancelled,
ConflictedOk,
ConflictedNotOk,
diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
index 4b88e42f31..997b090ff6 100644
--- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
@@ -12,18 +12,29 @@ namespace MediaBrowser.Model.LiveTv
[DebuggerDisplay("Name = {Name}")]
public class SeriesTimerInfoDto : BaseTimerInfoDto
{
+ public SeriesTimerInfoDto()
+ {
+ ImageTags = new Dictionary();
+ Days = new List();
+ Type = "SeriesTimer";
+ }
+
///
/// Gets or sets a value indicating whether [record any time].
///
/// true if [record any time]; otherwise, false.
public bool RecordAnyTime { get; set; }
+ public bool SkipEpisodesInLibrary { get; set; }
+
///
/// Gets or sets a value indicating whether [record any channel].
///
/// true if [record any channel]; otherwise, false.
public bool RecordAnyChannel { get; set; }
+ public int KeepUpTo { get; set; }
+
///
/// Gets or sets a value indicating whether [record new only].
///
@@ -58,10 +69,36 @@ namespace MediaBrowser.Model.LiveTv
get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Primary); }
}
- public SeriesTimerInfoDto()
- {
- ImageTags = new Dictionary();
- Days = new List();
- }
+ ///
+ /// Gets or sets the parent thumb item id.
+ ///
+ /// The parent thumb item id.
+ public string ParentThumbItemId { get; set; }
+
+ ///
+ /// Gets or sets the parent thumb image tag.
+ ///
+ /// The parent thumb image tag.
+ public string ParentThumbImageTag { get; set; }
+
+ ///
+ /// Gets or sets the parent primary image item identifier.
+ ///
+ /// The parent primary image item identifier.
+ public string ParentPrimaryImageItemId { get; set; }
+
+ ///
+ /// Gets or sets the parent primary image tag.
+ ///
+ /// The parent primary image tag.
+ public string ParentPrimaryImageTag { get; set; }
+ }
+
+ public enum KeepUntil
+ {
+ UntilDeleted,
+ UntilSpaceNeeded,
+ UntilWatched,
+ UntilDate
}
}
diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs
index a95678fae5..d1aa3118fb 100644
--- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs
@@ -27,8 +27,6 @@ namespace MediaBrowser.Model.LiveTv
/// The external series timer identifier.
public string ExternalSeriesTimerId { get; set; }
- public string Type { get; set; }
-
///
/// Gets or sets the run time ticks.
///
diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs
index 87b6b89acd..310dc486fe 100644
--- a/MediaBrowser.Model/LiveTv/TimerQuery.cs
+++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs
@@ -15,5 +15,7 @@
public string SeriesTimerId { get; set; }
public bool? IsActive { get; set; }
+
+ public bool? IsScheduled { get; set; }
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index db70b86063..b9b920588d 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -84,12 +84,8 @@
-
-
-
-
@@ -400,7 +396,6 @@
-
diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs
index f5e3624f00..eefd158080 100644
--- a/MediaBrowser.Model/Notifications/NotificationType.cs
+++ b/MediaBrowser.Model/Notifications/NotificationType.cs
@@ -16,7 +16,6 @@ namespace MediaBrowser.Model.Notifications
PluginUpdateInstalled,
PluginUninstalled,
NewLibraryContent,
- NewLibraryContentMultiple,
ServerRestartRequired,
TaskFailed,
CameraImageUploaded,
diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs
index 8c9e116d60..72b6632e4c 100644
--- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs
+++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs
@@ -32,7 +32,8 @@ namespace MediaBrowser.Model.Providers
public string SearchProviderName { get; set; }
public string GameSystem { get; set; }
-
+ public string Overview { get; set; }
+
public RemoteSearchResult()
{
ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase);
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index 0400e374af..fcacc621c5 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -130,6 +130,8 @@
///
Metascore,
+ OfficialRatingDescription,
+
OriginalTitle,
///
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index 3d1de5b379..022e03baf6 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -8,6 +8,8 @@ namespace MediaBrowser.Model.System
///
public class SystemInfo : PublicSystemInfo
{
+ public PackageVersionClass SystemUpdateLevel { get; set; }
+
///
/// Gets or sets the display name of the operating system.
///
@@ -32,6 +34,8 @@ namespace MediaBrowser.Model.System
/// The mac address.
public string MacAddress { get; set; }
+ public string PackageName { get; set; }
+
///
/// Gets or sets a value indicating whether this instance has pending restart.
///
diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs
index 191deeb8f1..208d5b784f 100644
--- a/MediaBrowser.Model/Updates/PackageInfo.cs
+++ b/MediaBrowser.Model/Updates/PackageInfo.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Updates
/// The internal id of this package.
///
/// The id.
- public int id { get; set; }
+ public string id { get; set; }
///
/// Gets or sets the name.
@@ -66,7 +66,7 @@ namespace MediaBrowser.Model.Updates
/// Gets or sets the type.
///
/// The type.
- public PackageType type { get; set; }
+ public string type { get; set; }
///
/// Gets or sets the target filename.
@@ -127,7 +127,7 @@ namespace MediaBrowser.Model.Updates
/// Gets or sets the total number of ratings for this package.
///
/// The total ratings.
- public int totalRatings { get; set; }
+ public int? totalRatings { get; set; }
///
/// Gets or sets the average rating for this package .
diff --git a/MediaBrowser.Model/Updates/PackageType.cs b/MediaBrowser.Model/Updates/PackageType.cs
deleted file mode 100644
index a00196e717..0000000000
--- a/MediaBrowser.Model/Updates/PackageType.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace MediaBrowser.Model.Updates
-{
- ///
- /// Enum PackageType
- ///
- public enum PackageType
- {
- ///
- /// All
- ///
- All,
- ///
- /// The system
- ///
- System,
- ///
- /// The user installed
- ///
- UserInstalled
- }
-}
\ No newline at end of file
diff --git a/MediaBrowser.Mono.sln b/MediaBrowser.Mono.sln
index 3d9677fa88..6300a95597 100644
--- a/MediaBrowser.Mono.sln
+++ b/MediaBrowser.Mono.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.30723.0
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}"
EndProject
@@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Startup
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Nat", "Mono.Nat\Mono.Nat.csproj", "{D7453B88-2266-4805-B39B-2B5A2A33E1BA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -203,6 +205,18 @@ Global
{08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|Any CPU.Build.0 = Release|Any CPU
{08FFF49B-F175-4807-A2B5-73B0EBD9F716}.Release|x86.ActiveCfg = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Debug|x86.Build.0 = Debug|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release Mono|Any CPU.Build.0 = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release Mono|x86.ActiveCfg = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release Mono|x86.Build.0 = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release|x86.ActiveCfg = Release|Any CPU
+ {D7453B88-2266-4805-B39B-2B5A2A33E1BA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs
index 88811c850d..87aaafb39f 100644
--- a/MediaBrowser.Providers/Chapters/ChapterManager.cs
+++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Chapters;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -22,7 +21,6 @@ namespace MediaBrowser.Providers.Chapters
{
public class ChapterManager : IChapterManager
{
- private IChapterProvider[] _providers;
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
@@ -36,224 +34,6 @@ namespace MediaBrowser.Providers.Chapters
_itemRepo = itemRepo;
}
- public void AddParts(IEnumerable chapterProviders)
- {
- _providers = chapterProviders.ToArray();
- }
-
- public Task> Search(Video video, CancellationToken cancellationToken)
- {
- VideoContentType mediaType;
-
- if (video is Episode)
- {
- mediaType = VideoContentType.Episode;
- }
- else if (video is Movie)
- {
- mediaType = VideoContentType.Movie;
- }
- else
- {
- // These are the only supported types
- return Task.FromResult>(new List());
- }
-
- var request = new ChapterSearchRequest
- {
- ContentType = mediaType,
- IndexNumber = video.IndexNumber,
- Language = video.GetPreferredMetadataLanguage(),
- MediaPath = video.Path,
- Name = video.Name,
- ParentIndexNumber = video.ParentIndexNumber,
- ProductionYear = video.ProductionYear,
- ProviderIds = video.ProviderIds,
- RuntimeTicks = video.RunTimeTicks,
- SearchAllProviders = false
- };
-
- var episode = video as Episode;
-
- if (episode != null)
- {
- request.IndexNumberEnd = episode.IndexNumberEnd;
- request.SeriesName = episode.SeriesName;
- }
-
- return Search(request, cancellationToken);
- }
-
- public async Task> Search(ChapterSearchRequest request, CancellationToken cancellationToken)
- {
- var contentType = request.ContentType;
- var providers = GetInternalProviders(false)
- .Where(i => i.SupportedMediaTypes.Contains(contentType))
- .ToList();
-
- // If not searching all, search one at a time until something is found
- if (!request.SearchAllProviders)
- {
- foreach (var provider in providers)
- {
- try
- {
- var currentResults = await Search(request, provider, cancellationToken).ConfigureAwait(false);
-
- if (currentResults.Count > 0)
- {
- return currentResults;
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error downloading subtitles from {0}", ex, provider.Name);
- }
- }
- return new List();
- }
-
- var tasks = providers.Select(async i =>
- {
- try
- {
- return await Search(request, i, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name);
- return new List();
- }
- });
-
- var results = await Task.WhenAll(tasks).ConfigureAwait(false);
-
- return results.SelectMany(i => i);
- }
-
- private async Task> Search(ChapterSearchRequest request,
- IChapterProvider provider,
- CancellationToken cancellationToken)
- {
- var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false);
-
- var list = searchResults.ToList();
-
- foreach (var result in list)
- {
- result.Id = GetProviderId(provider.Name) + "_" + result.Id;
- result.ProviderName = provider.Name;
- }
-
- return list;
- }
-
- public Task GetChapters(string id, CancellationToken cancellationToken)
- {
- var parts = id.Split(new[] { '_' }, 2);
-
- var provider = GetProvider(parts.First());
- id = parts.Last();
-
- return provider.GetChapters(id, cancellationToken);
- }
-
- public IEnumerable GetProviders(string itemId)
- {
- var video = _libraryManager.GetItemById(itemId) as Video;
- VideoContentType mediaType;
-
- if (video is Episode)
- {
- mediaType = VideoContentType.Episode;
- }
- else if (video is Movie)
- {
- mediaType = VideoContentType.Movie;
- }
- else
- {
- // These are the only supported types
- return new List();
- }
-
- var providers = GetInternalProviders(false)
- .Where(i => i.SupportedMediaTypes.Contains(mediaType));
-
- return GetInfos(providers);
- }
-
- public IEnumerable GetProviders()
- {
- return GetInfos(GetInternalProviders(true));
- }
-
- private IEnumerable GetInternalProviders(bool includeDisabledProviders)
- {
- var providers = _providers;
-
- if (!includeDisabledProviders)
- {
- var options = GetConfiguration();
-
- providers = providers
- .Where(i => !options.DisabledFetchers.Contains(i.Name))
- .ToArray();
- }
-
- return providers
- .OrderBy(GetConfiguredOrder)
- .ThenBy(GetDefaultOrder)
- .ToArray();
- }
-
- private IEnumerable GetInfos(IEnumerable providers)
- {
- return providers.Select(i => new ChapterProviderInfo
- {
- Name = i.Name,
- Id = GetProviderId(i.Name)
- });
- }
-
- private string GetProviderId(string name)
- {
- return name.ToLower().GetMD5().ToString("N");
- }
-
- private IChapterProvider GetProvider(string id)
- {
- return _providers.First(i => string.Equals(id, GetProviderId(i.Name)));
- }
-
- private int GetConfiguredOrder(IChapterProvider provider)
- {
- var options = GetConfiguration();
-
- // See if there's a user-defined order
- var index = Array.IndexOf(options.FetcherOrder, provider.Name);
-
- if (index != -1)
- {
- return index;
- }
-
- // Not configured. Just return some high number to put it at the end.
- return 100;
- }
-
- private int GetDefaultOrder(IChapterProvider provider)
- {
- var hasOrder = provider as IHasOrder;
-
- if (hasOrder != null)
- {
- return hasOrder.Order;
- }
-
- return 0;
- }
-
public IEnumerable GetChapters(string itemId)
{
return _itemRepo.GetChapters(new Guid(itemId));
diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
index cdaa383667..2f534c12e5 100644
--- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using CommonIO;
+using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -21,4 +22,17 @@ namespace MediaBrowser.Providers.Folders
{
}
}
+
+ public class ManualCollectionsFolderMetadataService : MetadataService
+ {
+ protected override void MergeData(MetadataResult source, MetadataResult target, List lockedFields, bool replaceData, bool mergeMetadataSettings)
+ {
+ ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
+ }
+
+ public ManualCollectionsFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager)
+ {
+ }
+ }
+
}
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
index 3a532257fe..b26f237151 100644
--- a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
+++ b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.GameGenres
public static string ProviderName
{
- get { return "Media Browser Designs"; }
+ get { return "Emby Designs"; }
}
public bool Supports(IHasImages item)
@@ -137,7 +137,7 @@ namespace MediaBrowser.Providers.GameGenres
{
CancellationToken = cancellationToken,
Url = url,
- ResourcePool = GenreImageProvider.ImageDownloadResourcePool
+ BufferContent = false
});
}
}
diff --git a/MediaBrowser.Providers/Genres/GenreImageProvider.cs b/MediaBrowser.Providers/Genres/GenreImageProvider.cs
index 7c2ed00a61..954cd008e3 100644
--- a/MediaBrowser.Providers/Genres/GenreImageProvider.cs
+++ b/MediaBrowser.Providers/Genres/GenreImageProvider.cs
@@ -22,8 +22,6 @@ namespace MediaBrowser.Providers.Genres
private readonly SemaphoreSlim _listResourcePool = new SemaphoreSlim(1, 1);
- public static SemaphoreSlim ImageDownloadResourcePool = new SemaphoreSlim(5, 5);
-
public GenreImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
{
_config = config;
@@ -38,7 +36,7 @@ namespace MediaBrowser.Providers.Genres
public static string ProviderName
{
- get { return "Media Browser Designs"; }
+ get { return "Emby Designs"; }
}
public bool Supports(IHasImages item)
@@ -138,7 +136,7 @@ namespace MediaBrowser.Providers.Genres
{
CancellationToken = cancellationToken,
Url = url,
- ResourcePool = ImageDownloadResourcePool
+ BufferContent = false
});
}
}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 3de3305578..5203adc9d1 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -38,6 +38,7 @@ namespace MediaBrowser.Providers.Manager
private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
+ private readonly IMemoryStreamProvider _memoryStreamProvider;
///
/// Initializes a new instance of the class.
@@ -46,12 +47,13 @@ namespace MediaBrowser.Providers.Manager
/// The directory watchers.
/// The file system.
/// The logger.
- public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
+ public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger, IMemoryStreamProvider memoryStreamProvider)
{
_config = config;
_libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_logger = logger;
+ _memoryStreamProvider = memoryStreamProvider;
}
///
@@ -124,7 +126,7 @@ namespace MediaBrowser.Providers.Manager
var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
// If there are more than one output paths, the stream will need to be seekable
- var memoryStream = new MemoryStream();
+ var memoryStream = _memoryStreamProvider.CreateNew();
using (source)
{
await source.CopyToAsync(memoryStream).ConfigureAwait(false);
@@ -211,6 +213,20 @@ namespace MediaBrowser.Providers.Manager
throw;
}
}
+ catch (IOException ex)
+ {
+ var retry = !string.IsNullOrWhiteSpace(retryPath) &&
+ !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase);
+
+ if (retry)
+ {
+ _logger.Error("IOException saving to {0}. {2}. Will retry saving to {1}", path, retryPath, ex.Message);
+ }
+ else
+ {
+ throw;
+ }
+ }
source.Position = 0;
await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
@@ -355,7 +371,7 @@ namespace MediaBrowser.Providers.Manager
return Path.Combine(seriesFolder, imageFilename);
}
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return GetSavePathForItemInMixedFolder(item, type, "landscape", extension);
}
@@ -431,7 +447,7 @@ namespace MediaBrowser.Providers.Manager
path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension);
}
- else if (item.IsInMixedFolder)
+ else if (item.DetectIsInMixedFolder())
{
path = GetSavePathForItemInMixedFolder(item, type, filename, extension);
}
@@ -498,7 +514,7 @@ namespace MediaBrowser.Providers.Manager
if (imageIndex.Value == 0)
{
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) };
}
@@ -524,7 +540,7 @@ namespace MediaBrowser.Providers.Manager
var outputIndex = imageIndex.Value;
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) };
}
@@ -567,7 +583,7 @@ namespace MediaBrowser.Providers.Manager
return new[] { Path.Combine(seasonFolder, imageFilename) };
}
- if (item.IsInMixedFolder || item is MusicVideo)
+ if (item.DetectIsInMixedFolder() || item is MusicVideo)
{
return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) };
}
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 97dd1ed4ca..87da835dcc 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.Manager
return hasChanges;
}
- public async Task RefreshImages(IHasImages item, IEnumerable imageProviders, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken)
+ public async Task RefreshImages(IHasImages item, LibraryOptions libraryOptions, IEnumerable imageProviders, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken)
{
if (refreshOptions.IsReplacingImage(ImageType.Backdrop))
{
@@ -84,7 +84,7 @@ namespace MediaBrowser.Providers.Manager
if (remoteProvider != null)
{
- await RefreshFromProvider(item, remoteProvider, refreshOptions, savedOptions, backdropLimit, screenshotLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false);
+ await RefreshFromProvider(item, libraryOptions, remoteProvider, refreshOptions, savedOptions, backdropLimit, screenshotLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false);
providerIds.Add(provider.GetType().FullName.GetMD5());
continue;
}
@@ -249,7 +249,7 @@ namespace MediaBrowser.Providers.Manager
/// The result.
/// The cancellation token.
/// Task.
- private async Task RefreshFromProvider(IHasImages item,
+ private async Task RefreshFromProvider(IHasImages item, LibraryOptions libraryOptions,
IRemoteImageProvider provider,
ImageRefreshOptions refreshOptions,
MetadataOptions savedOptions,
@@ -293,7 +293,7 @@ namespace MediaBrowser.Providers.Manager
if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
{
minWidth = savedOptions.GetMinWidth(imageType);
- var downloaded = await DownloadImage(item, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false);
+ var downloaded = await DownloadImage(item, libraryOptions, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false);
if (downloaded)
{
@@ -305,7 +305,7 @@ namespace MediaBrowser.Providers.Manager
if (!item.LockedFields.Contains(MetadataFields.Backdrops))
{
minWidth = savedOptions.GetMinWidth(ImageType.Backdrop);
- await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
+ await DownloadBackdrops(item, libraryOptions, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
}
if (!item.LockedFields.Contains(MetadataFields.Screenshots))
@@ -314,7 +314,7 @@ namespace MediaBrowser.Providers.Manager
if (hasScreenshots != null)
{
minWidth = savedOptions.GetMinWidth(ImageType.Screenshot);
- await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
+ await DownloadBackdrops(item, libraryOptions, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false);
}
}
}
@@ -472,7 +472,7 @@ namespace MediaBrowser.Providers.Manager
return changed;
}
- private async Task DownloadImage(IHasImages item,
+ private async Task DownloadImage(IHasImages item, LibraryOptions libraryOptions,
IRemoteImageProvider provider,
RefreshResult result,
IEnumerable images,
@@ -484,7 +484,7 @@ namespace MediaBrowser.Providers.Manager
.Where(i => i.Type == type && !(i.Width.HasValue && i.Width.Value < minWidth))
.ToList();
- if (EnableImageStub(item, type) && eligibleImages.Count > 0)
+ if (EnableImageStub(item, type, libraryOptions) && eligibleImages.Count > 0)
{
SaveImageStub(item, type, eligibleImages.Select(i => i.Url));
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
@@ -518,14 +518,14 @@ namespace MediaBrowser.Providers.Manager
return false;
}
- private bool EnableImageStub(IHasImages item, ImageType type)
+ private bool EnableImageStub(IHasImages item, ImageType type, LibraryOptions libraryOptions)
{
if (item is LiveTvProgram)
{
return true;
}
- if (_config.Configuration.DownloadImagesInAdvance)
+ if (libraryOptions.DownloadImagesInAdvance)
{
return false;
}
@@ -555,12 +555,6 @@ namespace MediaBrowser.Providers.Manager
return false;
case ImageType.Thumb:
return false;
- case ImageType.Logo:
- return false;
- case ImageType.Backdrop:
- return false;
- case ImageType.Screenshot:
- return false;
default:
return true;
}
@@ -585,7 +579,7 @@ namespace MediaBrowser.Providers.Manager
}, newIndex);
}
- private async Task DownloadBackdrops(IHasImages item, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable images, int minWidth, CancellationToken cancellationToken)
+ private async Task DownloadBackdrops(IHasImages item, LibraryOptions libraryOptions, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable images, int minWidth, CancellationToken cancellationToken)
{
foreach (var image in images.Where(i => i.Type == imageType))
{
@@ -601,7 +595,7 @@ namespace MediaBrowser.Providers.Manager
var url = image.Url;
- if (EnableImageStub(item, imageType))
+ if (EnableImageStub(item, imageType, libraryOptions))
{
SaveImageStub(item, imageType, new[] { url });
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index c535f33baf..c470f55f2b 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -11,6 +11,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Providers.Manager
@@ -120,6 +121,8 @@ namespace MediaBrowser.Providers.Manager
}
}
+ LibraryOptions libraryOptions = null;
+
// Next run remote image providers, but only if local image providers didn't throw an exception
if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
{
@@ -127,7 +130,12 @@ namespace MediaBrowser.Providers.Manager
if (providers.Count > 0)
{
- var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);
+ if (libraryOptions == null)
+ {
+ libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item);
+ }
+
+ var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);
updateType = updateType | result.UpdateType;
if (result.Failures == 0)
@@ -180,8 +188,13 @@ namespace MediaBrowser.Providers.Manager
item.DateLastRefreshed = default(DateTime);
}
+ if (libraryOptions == null)
+ {
+ libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item);
+ }
+
// Save to database
- await SaveItem(metadataResult, updateType, cancellationToken).ConfigureAwait(false);
+ await SaveItem(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false);
}
await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);
@@ -196,17 +209,19 @@ namespace MediaBrowser.Providers.Manager
lookupInfo.Year = result.ProductionYear;
}
- protected async Task SaveItem(MetadataResult result, ItemUpdateType reason, CancellationToken cancellationToken)
+ protected async Task SaveItem(MetadataResult result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken)
{
if (result.Item.SupportsPeople && result.People != null)
{
- await LibraryManager.UpdatePeople(result.Item as BaseItem, result.People.ToList());
- await SavePeopleMetadata(result.People, cancellationToken).ConfigureAwait(false);
+ var baseItem = result.Item as BaseItem;
+
+ await LibraryManager.UpdatePeople(baseItem, result.People.ToList());
+ await SavePeopleMetadata(result.People, libraryOptions, cancellationToken).ConfigureAwait(false);
}
await result.Item.UpdateToRepository(reason, cancellationToken).ConfigureAwait(false);
}
- private async Task SavePeopleMetadata(List people, CancellationToken cancellationToken)
+ private async Task SavePeopleMetadata(List people, LibraryOptions libraryOptions, CancellationToken cancellationToken)
{
foreach (var person in people)
{
@@ -229,7 +244,7 @@ namespace MediaBrowser.Providers.Manager
if (!string.IsNullOrWhiteSpace(person.ImageUrl) && !personEntity.HasImage(ImageType.Primary))
{
- await AddPersonImage(personEntity, person.ImageUrl, cancellationToken).ConfigureAwait(false);
+ await AddPersonImage(personEntity, libraryOptions, person.ImageUrl, cancellationToken).ConfigureAwait(false);
saveEntity = true;
updateType = updateType | ItemUpdateType.ImageUpdate;
@@ -243,9 +258,9 @@ namespace MediaBrowser.Providers.Manager
}
}
- private async Task AddPersonImage(Person personEntity, string imageUrl, CancellationToken cancellationToken)
+ private async Task AddPersonImage(Person personEntity, LibraryOptions libraryOptions, string imageUrl, CancellationToken cancellationToken)
{
- if (ServerConfigurationManager.Configuration.DownloadImagesInAdvance)
+ if (libraryOptions.DownloadImagesInAdvance)
{
try
{
@@ -301,6 +316,13 @@ namespace MediaBrowser.Providers.Manager
updateType |= ItemUpdateType.MetadataImport;
}
+ var inheritedTags = item.GetInheritedTags();
+ if (!inheritedTags.SequenceEqual(item.InheritedTags, StringComparer.Ordinal))
+ {
+ item.InheritedTags = inheritedTags;
+ updateType |= ItemUpdateType.MetadataImport;
+ }
+
return updateType;
}
@@ -517,7 +539,7 @@ namespace MediaBrowser.Providers.Manager
refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
// Only one local provider allowed per item
- if (IsFullLocalMetadata(localItem.Item))
+ if (item.IsLocked || IsFullLocalMetadata(localItem.Item))
{
hasLocalMetadata = true;
}
@@ -532,8 +554,6 @@ namespace MediaBrowser.Providers.Manager
}
catch (Exception ex)
{
- refreshResult.Failures++;
-
Logger.ErrorException("Error in {0}", ex, provider.Name);
// If a local provider fails, consider that a failure
@@ -631,6 +651,8 @@ namespace MediaBrowser.Providers.Manager
{
var refreshResult = new RefreshResult();
+ var results = new List>();
+
foreach (var provider in providers)
{
var providerName = provider.GetType().Name;
@@ -647,9 +669,7 @@ namespace MediaBrowser.Providers.Manager
if (result.HasMetadata)
{
- NormalizeRemoteResult(result.Item);
-
- MergeData(result, temp, new List(), false, false);
+ results.Add(result);
refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
}
@@ -670,20 +690,47 @@ namespace MediaBrowser.Providers.Manager
}
}
- return refreshResult;
- }
+ var orderedResults = new List>();
+ var preferredLanguage = NormalizeLanguage(id.MetadataLanguage);
- private void NormalizeRemoteResult(TItemType item)
- {
- if (!ServerConfigurationManager.Configuration.FindInternetTrailers)
+ // prioritize results with matching ResultLanguage
+ foreach (var result in results)
{
- var hasTrailers = item as IHasTrailers;
+ if (!result.QueriedById)
+ {
+ break;
+ }
- if (hasTrailers != null)
+ if (string.Equals(NormalizeLanguage(result.ResultLanguage), preferredLanguage, StringComparison.OrdinalIgnoreCase) && result.QueriedById)
{
- hasTrailers.RemoteTrailers.Clear();
+ orderedResults.Add(result);
}
}
+
+ // add all other results
+ foreach (var result in results)
+ {
+ if (!orderedResults.Contains(result))
+ {
+ orderedResults.Add(result);
+ }
+ }
+
+ foreach (var result in results)
+ {
+ MergeData(result, temp, new List(), false, false);
+ }
+
+ return refreshResult;
+ }
+
+ private string NormalizeLanguage(string language)
+ {
+ if (string.IsNullOrWhiteSpace(language))
+ {
+ return "en";
+ }
+ return language;
}
private void MergeNewData(TItemType source, TIdType lookupInfo)
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 25b9b4fd5e..ae1d60eb9f 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Common.IO;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Manager
@@ -57,13 +58,13 @@ namespace MediaBrowser.Providers.Manager
private IMetadataService[] _metadataServices = { };
private IMetadataProvider[] _metadataProviders = { };
private IEnumerable _savers;
- private IImageSaver[] _imageSavers;
private readonly IServerApplicationPaths _appPaths;
private readonly IJsonSerializer _json;
private IExternalId[] _externalIds;
private readonly Func _libraryManagerFactory;
+ private readonly IMemoryStreamProvider _memoryStreamProvider;
///
/// Initializes a new instance of the class.
@@ -73,7 +74,7 @@ namespace MediaBrowser.Providers.Manager
/// The directory watchers.
/// The log manager.
/// The file system.
- public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func libraryManagerFactory, IJsonSerializer json)
+ public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func libraryManagerFactory, IJsonSerializer json, IMemoryStreamProvider memoryStreamProvider)
{
_logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient;
@@ -83,26 +84,20 @@ namespace MediaBrowser.Providers.Manager
_appPaths = appPaths;
_libraryManagerFactory = libraryManagerFactory;
_json = json;
+ _memoryStreamProvider = memoryStreamProvider;
}
///
/// Adds the metadata providers.
///
- /// The image providers.
- /// The metadata services.
- /// The metadata providers.
- /// The metadata savers.
- /// The image savers.
- /// The external ids.
public void AddParts(IEnumerable imageProviders, IEnumerable metadataServices,
IEnumerable metadataProviders, IEnumerable metadataSavers,
- IEnumerable imageSavers, IEnumerable externalIds)
+ IEnumerable externalIds)
{
ImageProviders = imageProviders.ToArray();
_metadataServices = metadataServices.OrderBy(i => i.Order).ToArray();
_metadataProviders = metadataProviders.ToArray();
- _imageSavers = imageSavers.ToArray();
_externalIds = externalIds.OrderBy(i => i.Name).ToArray();
_savers = metadataSavers.Where(i =>
@@ -142,12 +137,12 @@ namespace MediaBrowser.Providers.Manager
public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
{
- return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
+ return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
}
public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
{
- return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
+ return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
}
public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
@@ -159,7 +154,7 @@ namespace MediaBrowser.Providers.Manager
var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
- return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
+ return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
}
public async Task> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index 5f23cf69c9..fabe08f334 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -99,6 +99,11 @@ namespace MediaBrowser.Providers.Manager
target.CustomRating = source.CustomRating;
}
+ if (replaceData || string.IsNullOrEmpty(target.Tagline))
+ {
+ target.Tagline = source.Tagline;
+ }
+
if (!lockedFields.Contains(MetadataFields.Overview))
{
if (replaceData || string.IsNullOrEmpty(target.Overview))
@@ -167,15 +172,9 @@ namespace MediaBrowser.Providers.Manager
if (!lockedFields.Contains(MetadataFields.ProductionLocations))
{
- var sourceHasProductionLocations = source as IHasProductionLocations;
- var targetHasProductionLocations = target as IHasProductionLocations;
-
- if (sourceHasProductionLocations != null && targetHasProductionLocations != null)
+ if (replaceData || target.ProductionLocations.Count == 0)
{
- if (replaceData || targetHasProductionLocations.ProductionLocations.Count == 0)
- {
- targetHasProductionLocations.ProductionLocations = sourceHasProductionLocations.ProductionLocations;
- }
+ target.ProductionLocations = source.ProductionLocations;
}
}
@@ -200,7 +199,6 @@ namespace MediaBrowser.Providers.Manager
MergeMetascore(source, target, lockedFields, replaceData);
MergeCriticRating(source, target, lockedFields, replaceData);
MergeAwards(source, target, lockedFields, replaceData);
- MergeTaglines(source, target, lockedFields, replaceData);
MergeTrailers(source, target, lockedFields, replaceData);
MergeShortOverview(source, target, lockedFields, replaceData);
@@ -330,20 +328,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- private static void MergeTaglines(BaseItem source, BaseItem target, List lockedFields, bool replaceData)
- {
- var sourceCast = source as IHasTaglines;
- var targetCast = target as IHasTaglines;
-
- if (sourceCast != null && targetCast != null)
- {
- if (replaceData || targetCast.Taglines.Count == 0)
- {
- targetCast.Taglines = sourceCast.Taglines;
- }
- }
- }
-
private static void MergeTrailers(BaseItem source, BaseItem target, List lockedFields, bool replaceData)
{
var sourceCast = source as IHasTrailers;
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 027341ee6a..68fc803711 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -162,7 +162,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var audio = item as Audio;
- return item.LocationType == LocationType.FileSystem && audio != null && !audio.IsArchive;
+ return item.LocationType == LocationType.FileSystem && audio != null;
}
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index baa5614878..afcf4b2260 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -38,13 +38,6 @@ namespace MediaBrowser.Providers.MediaInfo
public async Task Probe(T item, CancellationToken cancellationToken)
where T : Audio
{
- if (item.IsArchive)
- {
- var ext = Path.GetExtension(item.Path) ?? string.Empty;
- item.Container = ext.TrimStart('.');
- return ItemUpdateType.MetadataImport;
- }
-
var result = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index c208235356..be0b2ca6d7 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -72,13 +72,6 @@ namespace MediaBrowser.Providers.MediaInfo
CancellationToken cancellationToken)
where T : Video
{
- if (item.IsArchive)
- {
- var ext = Path.GetExtension(item.Path) ?? string.Empty;
- item.Container = ext.TrimStart('.');
- return ItemUpdateType.MetadataImport;
- }
-
var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
BlurayDiscInfo blurayDiscInfo = null;
@@ -238,22 +231,6 @@ namespace MediaBrowser.Providers.MediaInfo
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
options.MetadataRefreshMode == MetadataRefreshMode.Default)
{
- var chapterOptions = _chapterManager.GetConfiguration();
-
- try
- {
- var remoteChapters = await DownloadChapters(video, chapters, chapterOptions, cancellationToken).ConfigureAwait(false);
-
- if (remoteChapters.Count > 0)
- {
- chapters = remoteChapters;
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error downloading chapters", ex);
- }
-
if (chapters.Count == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
{
AddDummyChapters(video, chapters);
@@ -261,11 +238,18 @@ namespace MediaBrowser.Providers.MediaInfo
NormalizeChapterNames(chapters);
+ var libraryOptions = _libraryManager.GetLibraryOptions(video);
+ var extractDuringScan = false;
+ if (libraryOptions != null)
+ {
+ extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan;
+ }
+
await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
{
Chapters = chapters,
Video = video,
- ExtractImages = chapterOptions.ExtractDuringLibraryScan,
+ ExtractImages = extractDuringScan,
SaveChapters = false
}, cancellationToken).ConfigureAwait(false);
@@ -554,52 +538,6 @@ namespace MediaBrowser.Providers.MediaInfo
currentStreams.AddRange(externalSubtitleStreams);
}
- private async Task> DownloadChapters(Video video, List currentChapters, ChapterOptions options, CancellationToken cancellationToken)
- {
- if ((options.DownloadEpisodeChapters &&
- video is Episode) ||
- (options.DownloadMovieChapters &&
- video is Movie))
- {
- var results = await _chapterManager.Search(video, cancellationToken).ConfigureAwait(false);
-
- var result = results.FirstOrDefault();
-
- if (result != null)
- {
- var chapters = await _chapterManager.GetChapters(result.Id, cancellationToken).ConfigureAwait(false);
-
- var chapterInfos = chapters.Chapters.Select(i => new ChapterInfo
- {
- Name = i.Name,
- StartPositionTicks = i.StartPositionTicks
-
- }).ToList();
-
- if (chapterInfos.All(i => i.StartPositionTicks == 0))
- {
- if (currentChapters.Count >= chapterInfos.Count)
- {
- var index = 0;
- foreach (var info in chapterInfos)
- {
- info.StartPositionTicks = currentChapters[index].StartPositionTicks;
- index++;
- }
- }
- else
- {
- chapterInfos.Clear();
- }
- }
-
- return chapterInfos;
- }
- }
-
- return new List();
- }
-
///
/// The dummy chapter duration
///
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index f64b7b7927..024171f40d 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -117,7 +117,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
get
{
- return new[] { ".srt", ".ssa", ".ass", ".sub" };
+ return new[] { ".srt", ".ssa", ".ass", ".sub", ".smi", ".sami" };
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
index 79da291b77..2490f71453 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
@@ -14,6 +14,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using System.IO;
+using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -24,14 +26,16 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly ISubtitleManager _subtitleManager;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILogger _logger;
+ private IJsonSerializer _json;
- public SubtitleScheduledTask(ILibraryManager libraryManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, IMediaSourceManager mediaSourceManager)
+ public SubtitleScheduledTask(ILibraryManager libraryManager, IJsonSerializer json, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, IMediaSourceManager mediaSourceManager)
{
_libraryManager = libraryManager;
_config = config;
_subtitleManager = subtitleManager;
_logger = logger;
_mediaSourceManager = mediaSourceManager;
+ _json = json;
}
public string Name
@@ -58,38 +62,65 @@ namespace MediaBrowser.Providers.MediaInfo
{
var options = GetOptions();
- var videos = _libraryManager.RootFolder
- .GetRecursiveChildren(i =>
- {
- if (!(i is Video))
- {
- return false;
- }
+ var types = new List();
- if (i.LocationType == LocationType.Remote || i.LocationType == LocationType.Virtual)
- {
- return false;
- }
+ if (options.DownloadEpisodeSubtitles)
+ {
+ types.Add("Episode");
+ }
+ if (options.DownloadMovieSubtitles)
+ {
+ types.Add("Movie");
+ }
- return (options.DownloadEpisodeSubtitles &&
- i is Episode) ||
- (options.DownloadMovieSubtitles &&
- i is Movie);
- })
- .Cast