aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Drawing/ImageProcessor.cs13
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj4
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs1
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs28
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs6
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveStream.cs1
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Net/IHttpResultFactory.cs8
-rw-r--r--MediaBrowser.Controller/Providers/IImageFileSaver.cs20
-rw-r--r--MediaBrowser.Controller/Providers/IImageSaver.cs11
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs7
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs2
-rw-r--r--MediaBrowser.Dlna/Eventing/EventManager.cs1
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs4
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Notifications/NotificationType.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs10
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs10
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs3
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs17
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs10
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs23
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs240
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs18
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs30
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs24
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs33
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs132
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs19
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs19
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs38
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs196
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs96
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs93
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-US.json1
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj3
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs7
-rw-r--r--MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs63
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs15
-rw-r--r--MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs272
-rw-r--r--MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj1
53 files changed, 484 insertions, 1075 deletions
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 80ebbb719..e9f8f81f3 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/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index a98637650..96d7874f0 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -197,6 +197,10 @@
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
+ <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
+ <Name>MediaBrowser.Server.Implementations</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index ebb3204a4..4c5abc996 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -116,6 +116,7 @@ namespace MediaBrowser.Api
config.EnableCaseSensitiveItemIds = true;
//config.EnableFolderView = true;
config.SchemaVersion = 109;
+ config.EnableSimpleArtistDetection = true;
}
public void Post(UpdateStartupConfiguration request)
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index be88c535e..90a22b217 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -116,6 +116,22 @@ namespace MediaBrowser.Controller.Entities
public bool IsInMixedFolder { get; set; }
[IgnoreDataMember]
+ protected virtual bool SupportsIsInMixedFolderDetection
+ {
+ get { return false; }
+ }
+
+ public bool DetectIsInMixedFolder()
+ {
+ if (SupportsIsInMixedFolderDetection)
+ {
+
+ }
+
+ return IsInMixedFolder;
+ }
+
+ [IgnoreDataMember]
public virtual bool SupportsRemoteImageDownloading
{
get
@@ -1116,7 +1132,7 @@ namespace MediaBrowser.Controller.Entities
var hasThemeMedia = this as IHasThemeMedia;
if (hasThemeMedia != null)
{
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
themeSongsChanged = await RefreshThemeSongs(hasThemeMedia, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -1266,7 +1282,15 @@ namespace MediaBrowser.Controller.Entities
{
var current = this;
- return current.IsInMixedFolder == newItem.IsInMixedFolder;
+ if (!SupportsIsInMixedFolderDetection)
+ {
+ if (current.IsInMixedFolder != newItem.IsInMixedFolder)
+ {
+ return false;
+ }
+ }
+
+ return true;
}
public void AfterMetadataRefresh()
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index 24910498f..a48b9f564 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -98,7 +98,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<string> GetDeletePaths()
{
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
return new[] { System.IO.Path.GetDirectoryName(Path) };
}
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
index a38b7394d..1ab0566e0 100644
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ b/MediaBrowser.Controller/Entities/IHasImages.cs
@@ -150,11 +150,7 @@ namespace MediaBrowser.Controller.Entities
/// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
bool SupportsLocalMetadata { get; }
- /// <summary>
- /// Gets a value indicating whether this instance is in mixed folder.
- /// </summary>
- /// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
- bool IsInMixedFolder { get; }
+ bool DetectIsInMixedFolder();
/// <summary>
/// Gets a value indicating whether this instance is locked.
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index f0270497c..e1e336147 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities.Movies
// Must have a parent to have special features
// In other words, it must be part of the Parent/Child tree
- if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder)
+ if (LocationType == LocationType.FileSystem && GetParent() != null && !DetectIsInMixedFolder())
{
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -119,7 +119,7 @@ namespace MediaBrowser.Controller.Entities.Movies
{
var info = GetItemLookupInfo<MovieInfo>();
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
}
@@ -145,7 +145,7 @@ namespace MediaBrowser.Controller.Entities.Movies
else
{
// Try to get the year from the folder name
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index 8b749b7a5..9254802dd 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -37,6 +37,15 @@ namespace MediaBrowser.Controller.Entities
}
}
+ [IgnoreDataMember]
+ protected override bool SupportsIsInMixedFolderDetection
+ {
+ get
+ {
+ return true;
+ }
+ }
+
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
@@ -65,7 +74,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 7a987a68e..f68cd2c85 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -64,7 +64,7 @@ namespace MediaBrowser.Controller.Entities
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
- if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
+ if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem)
{
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
}
@@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 1406a05ce..c64cdf57d 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -480,7 +480,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<string> GetDeletePaths()
{
- if (!IsInMixedFolder)
+ if (!DetectIsInMixedFolder())
{
return new[] { ContainingFolderPath };
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs
index 7d44fbd90..a5d432a54 100644
--- a/MediaBrowser.Controller/LiveTv/LiveStream.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs
@@ -14,6 +14,7 @@ namespace MediaBrowser.Controller.LiveTv
public ITunerHost TunerHost { get; set; }
public string OriginalStreamId { get; set; }
public bool EnableStreamSharing { get; set; }
+ public string UniqueId = Guid.NewGuid().ToString("N");
public LiveStream(MediaSourceInfo mediaSource)
{
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index e9d2054da..7c1114e22 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -287,9 +287,7 @@
<Compile Include="Providers\IHasItemChangeMonitor.cs" />
<Compile Include="Providers\IHasLookupInfo.cs" />
<Compile Include="Providers\IHasOrder.cs" />
- <Compile Include="Providers\IImageFileSaver.cs" />
<Compile Include="Providers\IImageProvider.cs" />
- <Compile Include="Providers\IImageSaver.cs" />
<Compile Include="Providers\ILocalImageFileProvider.cs" />
<Compile Include="Providers\ILocalMetadataProvider.cs" />
<Compile Include="Providers\ImageRefreshMode.cs" />
diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
index 8fdb1ce37..ca453840f 100644
--- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs
+++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
@@ -12,14 +12,6 @@ namespace MediaBrowser.Controller.Net
public interface IHttpResultFactory
{
/// <summary>
- /// Throws the error.
- /// </summary>
- /// <param name="statusCode">The status code.</param>
- /// <param name="errorMessage">The error message.</param>
- /// <param name="responseHeaders">The response headers.</param>
- void ThrowError(int statusCode, string errorMessage, IDictionary<string, string> responseHeaders = null);
-
- /// <summary>
/// Gets the result.
/// </summary>
/// <param name="content">The content.</param>
diff --git a/MediaBrowser.Controller/Providers/IImageFileSaver.cs b/MediaBrowser.Controller/Providers/IImageFileSaver.cs
deleted file mode 100644
index 3e11d8bf8..000000000
--- a/MediaBrowser.Controller/Providers/IImageFileSaver.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Collections.Generic;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Controller.Providers
-{
- public interface IImageFileSaver : IImageSaver
- {
- /// <summary>
- /// Gets the save paths.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="type">The type.</param>
- /// <param name="format">The format.</param>
- /// <param name="index">The index.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index);
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageSaver.cs b/MediaBrowser.Controller/Providers/IImageSaver.cs
deleted file mode 100644
index 62017160f..000000000
--- a/MediaBrowser.Controller/Providers/IImageSaver.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public interface IImageSaver
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 3eefa9647..d3e5685bb 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -95,15 +95,8 @@ namespace MediaBrowser.Controller.Providers
/// <summary>
/// Adds the metadata providers.
/// </summary>
- /// <param name="imageProviders">The image providers.</param>
- /// <param name="metadataServices">The metadata services.</param>
- /// <param name="metadataProviders">The metadata providers.</param>
- /// <param name="savers">The savers.</param>
- /// <param name="imageSavers">The image savers.</param>
- /// <param name="externalIds">The external ids.</param>
void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, IEnumerable<IMetadataProvider> metadataProviders,
IEnumerable<IMetadataSaver> savers,
- IEnumerable<IImageSaver> imageSavers,
IEnumerable<IExternalId> externalIds);
/// <summary>
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index 63cc48058..8de11b743 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Providers
{
Path = item.Path;
ContainingFolderPath = item.ContainingFolderPath;
- IsInMixedFolder = item.IsInMixedFolder;
+ IsInMixedFolder = item.DetectIsInMixedFolder();
var video = item as Video;
if (video != null)
diff --git a/MediaBrowser.Dlna/Eventing/EventManager.cs b/MediaBrowser.Dlna/Eventing/EventManager.cs
index 68f012c3a..51c8d2d91 100644
--- a/MediaBrowser.Dlna/Eventing/EventManager.cs
+++ b/MediaBrowser.Dlna/Eventing/EventManager.cs
@@ -156,7 +156,6 @@ namespace MediaBrowser.Dlna.Eventing
}
catch (OperationCanceledException)
{
- throw;
}
catch
{
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index fe61a7a46..ef9160b70 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -132,7 +132,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
var imagePrefix = item.FileNameWithoutExtension + "-";
- var isInMixedFolder = item.IsInMixedFolder;
+ var isInMixedFolder = item.DetectIsInMixedFolder();
PopulatePrimaryImages(item, images, files, imagePrefix, isInMixedFolder);
diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
index a90789a3e..5592c068c 100644
--- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.LocalMetadata.Savers
public static string GetGameSavePath(Game item)
{
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return Path.ChangeExtension(item.Path, ".xml");
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
index 33e90743a..5d0f1f075 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
@@ -76,7 +76,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public static string GetProbeSizeArgument(bool isDvd)
{
- return isDvd ? "-probesize 1G -analyzeduration 200M" : " -analyzeduration 2M";
+ return isDvd ? "-probesize 1G -analyzeduration 200M" : "";
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 25ad14fe8..5c3345008 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -426,8 +426,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
+ var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol);
+
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
- GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
+ probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
}
/// <summary>
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 1d2928f67..e7f8e6548 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -203,6 +203,7 @@ namespace MediaBrowser.Model.Configuration
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; }
/// <summary>
diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs
index f5e3624f0..eefd15808 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.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index c9b3f22c5..5203adc9d 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -371,7 +371,7 @@ namespace MediaBrowser.Providers.Manager
return Path.Combine(seriesFolder, imageFilename);
}
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return GetSavePathForItemInMixedFolder(item, type, "landscape", extension);
}
@@ -447,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);
}
@@ -514,7 +514,7 @@ namespace MediaBrowser.Providers.Manager
if (imageIndex.Value == 0)
{
- if (item.IsInMixedFolder)
+ if (item.DetectIsInMixedFolder())
{
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) };
}
@@ -540,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) };
}
@@ -583,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/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 7e28254b0..ae1d60eb9 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -58,7 +58,6 @@ namespace MediaBrowser.Providers.Manager
private IMetadataService[] _metadataServices = { };
private IMetadataProvider[] _metadataProviders = { };
private IEnumerable<IMetadataSaver> _savers;
- private IImageSaver[] _imageSavers;
private readonly IServerApplicationPaths _appPaths;
private readonly IJsonSerializer _json;
@@ -91,21 +90,14 @@ namespace MediaBrowser.Providers.Manager
/// <summary>
/// Adds the metadata providers.
/// </summary>
- /// <param name="imageProviders">The image providers.</param>
- /// <param name="metadataServices">The metadata services.</param>
- /// <param name="metadataProviders">The metadata providers.</param>
- /// <param name="metadataSavers">The metadata savers.</param>
- /// <param name="imageSavers">The image savers.</param>
- /// <param name="externalIds">The external ids.</param>
public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices,
IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers,
- IEnumerable<IImageSaver> imageSavers, IEnumerable<IExternalId> externalIds)
+ IEnumerable<IExternalId> 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 =>
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index ca4f1b956..2572a4f58 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.TV
private readonly ILibraryManager _libraryManager;
private readonly IMemoryStreamProvider _memoryStreamProvider;
- public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager)
+ public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IMemoryStreamProvider memoryStreamProvider)
{
_zipClient = zipClient;
_httpClient = httpClient;
@@ -49,6 +49,7 @@ namespace MediaBrowser.Providers.TV
_config = config;
_logger = logger;
_libraryManager = libraryManager;
+ _memoryStreamProvider = memoryStreamProvider;
Current = this;
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
index e84b66c5a..f7fe707da 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
@@ -377,10 +377,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
DisposeLibraryUpdateTimer();
}
- if (items.Count == 1)
- {
- var item = items.First();
+ items = items.Take(10).ToList();
+ foreach (var item in items)
+ {
var notification = new NotificationRequest
{
NotificationType = NotificationType.NewLibraryContent.ToString()
@@ -390,17 +390,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
await SendNotification(notification).ConfigureAwait(false);
}
- else
- {
- var notification = new NotificationRequest
- {
- NotificationType = NotificationType.NewLibraryContentMultiple.ToString()
- };
-
- notification.Variables["ItemCount"] = items.Count.ToString(CultureInfo.InvariantCulture);
-
- await SendNotification(notification).ConfigureAwait(false);
- }
}
public static string GetItemName(BaseItem item)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 7dc6fbb25..2ebeb0d44 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -94,12 +94,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer
// The Markdown feature causes slow startup times (5 mins+) on cold boots for some users
// Custom format allows images
- HostConfig.Instance.EnableFeatures = Feature.Csv | Feature.Html | Feature.Json | Feature.Jsv | Feature.Metadata | Feature.Xml | Feature.CustomFormat;
+ HostConfig.Instance.EnableFeatures = Feature.Html | Feature.Json | Feature.CustomFormat;
container.Adapter = _containerAdapter;
Plugins.RemoveAll(x => x is NativeTypesFeature);
- Plugins.Add(new SwaggerFeature());
+ //Plugins.Add(new SwaggerFeature());
Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"));
//Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
@@ -546,8 +546,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
}
-
- throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo);
+ else
+ {
+ httpRes.Close();
+ }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index 04085d3c7..10d6f7493 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -683,29 +683,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
- /// <summary>
- /// Gets the error result.
- /// </summary>
- /// <param name="statusCode">The status code.</param>
- /// <param name="errorMessage">The error message.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <returns>System.Object.</returns>
- public void ThrowError(int statusCode, string errorMessage, IDictionary<string, string> responseHeaders = null)
- {
- var error = new HttpError
- {
- Status = statusCode,
- ErrorCode = errorMessage
- };
-
- if (responseHeaders != null)
- {
- AddResponseHeaders(error, responseHeaders);
- }
-
- throw error;
- }
-
public object GetAsyncStreamWriter(IAsyncStreamSource streamSource)
{
return new AsyncStreamWriter(streamSource);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs
deleted file mode 100644
index cac2f8e09..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs
+++ /dev/null
@@ -1,240 +0,0 @@
-using MediaBrowser.Common.Events;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Net.WebSockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType;
-using WebSocketState = MediaBrowser.Model.Net.WebSocketState;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- /// <summary>
- /// Class NativeWebSocket
- /// </summary>
- public class NativeWebSocket : IWebSocket
- {
- /// <summary>
- /// The logger
- /// </summary>
- private readonly ILogger _logger;
-
- public event EventHandler<EventArgs> Closed;
-
- /// <summary>
- /// Gets or sets the web socket.
- /// </summary>
- /// <value>The web socket.</value>
- private System.Net.WebSockets.WebSocket WebSocket { get; set; }
-
- private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="NativeWebSocket" /> class.
- /// </summary>
- /// <param name="socket">The socket.</param>
- /// <param name="logger">The logger.</param>
- /// <exception cref="System.ArgumentNullException">socket</exception>
- public NativeWebSocket(WebSocket socket, ILogger logger)
- {
- if (socket == null)
- {
- throw new ArgumentNullException("socket");
- }
-
- if (logger == null)
- {
- throw new ArgumentNullException("logger");
- }
-
- _logger = logger;
- WebSocket = socket;
-
- Receive();
- }
-
- /// <summary>
- /// Gets or sets the state.
- /// </summary>
- /// <value>The state.</value>
- public WebSocketState State
- {
- get
- {
- WebSocketState commonState;
-
- if (!Enum.TryParse(WebSocket.State.ToString(), true, out commonState))
- {
- _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.State.ToString());
- }
-
- return commonState;
- }
- }
-
- /// <summary>
- /// Receives this instance.
- /// </summary>
- private async void Receive()
- {
- while (true)
- {
- byte[] bytes;
-
- try
- {
- bytes = await ReceiveBytesAsync(_cancellationTokenSource.Token).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- break;
- }
- catch (WebSocketException ex)
- {
- _logger.ErrorException("Error receiving web socket message", ex);
-
- break;
- }
-
- if (bytes == null)
- {
- // Connection closed
- EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger);
- break;
- }
-
- if (OnReceiveBytes != null)
- {
- OnReceiveBytes(bytes);
- }
- }
- }
-
- /// <summary>
- /// Receives the async.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{WebSocketMessageInfo}.</returns>
- /// <exception cref="System.Net.WebSockets.WebSocketException">Connection closed</exception>
- private async Task<byte[]> ReceiveBytesAsync(CancellationToken cancellationToken)
- {
- var bytes = new byte[4096];
- var buffer = new ArraySegment<byte>(bytes);
-
- var result = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false);
-
- if (result.CloseStatus.HasValue)
- {
- _logger.Info("Web socket connection closed by client. Reason: {0}", result.CloseStatus.Value);
- return null;
- }
-
- return buffer.Array;
- }
-
- /// <summary>
- /// Sends the async.
- /// </summary>
- /// <param name="bytes">The bytes.</param>
- /// <param name="type">The type.</param>
- /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken)
- {
- System.Net.WebSockets.WebSocketMessageType nativeType;
-
- if (!Enum.TryParse(type.ToString(), true, out nativeType))
- {
- _logger.Warn("Unrecognized WebSocketMessageType: {0}", type.ToString());
- }
-
- var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token);
-
- return WebSocket.SendAsync(new ArraySegment<byte>(bytes), nativeType, true, linkedTokenSource.Token);
- }
-
- public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken)
- {
- var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token);
-
- return WebSocket.SendAsync(new ArraySegment<byte>(bytes), System.Net.WebSockets.WebSocketMessageType.Binary, true, linkedTokenSource.Token);
- }
-
- public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken)
- {
- var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token);
-
- var bytes = Encoding.UTF8.GetBytes(text);
-
- return WebSocket.SendAsync(new ArraySegment<byte>(bytes), System.Net.WebSockets.WebSocketMessageType.Text, true, linkedTokenSource.Token);
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- _cancellationTokenSource.Cancel();
-
- WebSocket.Dispose();
- }
- }
-
- /// <summary>
- /// Gets or sets the receive action.
- /// </summary>
- /// <value>The receive action.</value>
- public Action<byte[]> OnReceiveBytes { get; set; }
-
- /// <summary>
- /// Gets or sets the on receive.
- /// </summary>
- /// <value>The on receive.</value>
- public Action<string> OnReceive { get; set; }
-
- /// <summary>
- /// The _supports native web socket
- /// </summary>
- private static bool? _supportsNativeWebSocket;
-
- /// <summary>
- /// Gets a value indicating whether [supports web sockets].
- /// </summary>
- /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value>
- public static bool IsSupported
- {
- get
- {
- if (!_supportsNativeWebSocket.HasValue)
- {
- try
- {
- new ClientWebSocket();
-
- _supportsNativeWebSocket = true;
- }
- catch (PlatformNotSupportedException)
- {
- _supportsNativeWebSocket = false;
- }
- }
-
- return _supportsNativeWebSocket.Value;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 488c630fe..4b94095f5 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -191,15 +191,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
}
- catch (IOException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in range request writer", ex);
- throw;
- }
finally
{
if (OnComplete != null)
@@ -251,15 +242,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
}
- catch (IOException ex)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in range request writer", ex);
- throw;
- }
finally
{
if (OnComplete != null)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index e08be8bd1..a58645ec5 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -81,20 +81,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
public void Write(string text)
{
- try
- {
- var bOutput = System.Text.Encoding.UTF8.GetBytes(text);
- response.ContentLength64 = bOutput.Length;
+ var bOutput = System.Text.Encoding.UTF8.GetBytes(text);
+ response.ContentLength64 = bOutput.Length;
- var outputStream = response.OutputStream;
- outputStream.Write(bOutput, 0, bOutput.Length);
- Close();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Could not WriteTextToResponse: " + ex.Message, ex);
- throw;
- }
+ var outputStream = response.OutputStream;
+ outputStream.Write(bOutput, 0, bOutput.Length);
+ Close();
}
public void Close()
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index b2bddc70d..f7661f55b 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -2463,7 +2463,7 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
+ var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
.SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
.ToList();
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index e819af06f..dadcff877 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -7,6 +7,7 @@ using System;
using System.IO;
using System.Linq;
using CommonIO;
+using MediaBrowser.Controller.Configuration;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
@@ -18,12 +19,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _config;
- public MusicArtistResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager)
+ public MusicArtistResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IServerConfigurationManager config)
{
_logger = logger;
_fileSystem = fileSystem;
_libraryManager = libraryManager;
+ _config = config;
}
/// <summary>
@@ -67,6 +70,19 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
return null;
}
+ if (args.IsDirectory)
+ {
+ if (args.ContainsFileSystemEntryByName("artist.nfo"))
+ {
+ return new MusicArtist();
+ }
+ }
+
+ if (_config.Configuration.EnableSimpleArtistDetection)
+ {
+ return null;
+ }
+
var directoryService = args.DirectoryService;
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index ee9533d2a..c3d5f3441 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -48,12 +48,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
string collectionType,
IDirectoryService directoryService)
{
- if (parent != null && parent.Path != null && parent.Path.IndexOf("disney", StringComparison.OrdinalIgnoreCase) != -1)
- {
- var b = true;
- var a = b;
- }
-
var result = ResolveMultipleInternal(parent, files, collectionType, directoryService);
if (result != null)
@@ -213,26 +207,22 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Find movies with their own folders
if (args.IsDirectory)
{
- var files = args.FileSystemChildren
- .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
- .ToList();
-
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+ return null;
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+ return null;
}
if (string.IsNullOrEmpty(collectionType))
{
- // Owned items should just use the plain video type
+ // Owned items will be caught by the plain video resolver
if (args.Parent == null)
{
- return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+ return null;
}
if (args.HasParent<Series>())
@@ -240,11 +230,21 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
return null;
}
- return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+ {
+ var files = args.FileSystemChildren
+ .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
+ .ToList();
+
+ return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+ }
}
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
+ var files = args.FileSystemChildren
+ .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
+ .ToList();
+
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index 307cf4cd2..ec8ac1a42 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -61,16 +61,7 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var key in keys)
{
- try
- {
- await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving user data", ex);
-
- throw;
- }
+ await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
}
var cacheKey = GetCacheKey(userId, item.Id);
@@ -107,18 +98,7 @@ namespace MediaBrowser.Server.Implementations.Library
cancellationToken.ThrowIfCancellationRequested();
- try
- {
- await Repository.SaveAllUserData(userId, userData, cancellationToken).ConfigureAwait(false);
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving user data", ex);
-
- throw;
- }
-
+ await Repository.SaveAllUserData(userId, userData, cancellationToken).ConfigureAwait(false);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 5b99849cd..23066149a 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -841,21 +841,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return new Tuple<MediaSourceInfo, IDirectStreamProvider>(result.Item2, result.Item1 as IDirectStreamProvider);
}
- private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId, bool enableStreamSharing)
+ private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, bool enableStreamSharing)
{
var json = _jsonSerializer.SerializeToString(mediaSource);
mediaSource = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
mediaSource.Id = Guid.NewGuid().ToString("N") + "_" + mediaSource.Id;
- if (mediaSource.DateLiveStreamOpened.HasValue && enableStreamSharing)
+ //if (mediaSource.DateLiveStreamOpened.HasValue && enableStreamSharing)
+ //{
+ // var ticks = (DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value).Ticks - TimeSpan.FromSeconds(10).Ticks;
+ // ticks = Math.Max(0, ticks);
+ // mediaSource.Path += "?t=" + ticks.ToString(CultureInfo.InvariantCulture) + "&s=" + mediaSource.DateLiveStreamOpened.Value.Ticks.ToString(CultureInfo.InvariantCulture);
+ //}
+
+ return mediaSource;
+ }
+
+ public async Task<LiveStream> GetLiveStream(string uniqueId)
+ {
+ await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
+
+ try
+ {
+ return _liveStreams.Values
+ .FirstOrDefault(i => string.Equals(i.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase));
+ }
+ finally
{
- var ticks = (DateTime.UtcNow - mediaSource.DateLiveStreamOpened.Value).Ticks - TimeSpan.FromSeconds(10).Ticks;
- ticks = Math.Max(0, ticks);
- mediaSource.Path += "?t=" + ticks.ToString(CultureInfo.InvariantCulture) + "&s=" + mediaSource.DateLiveStreamOpened.Value.Ticks.ToString(CultureInfo.InvariantCulture);
+ _liveStreamsSemaphore.Release();
}
- return mediaSource;
}
private async Task<Tuple<LiveStream, MediaSourceInfo, ITunerHost>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
@@ -872,7 +888,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
- var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1, result.EnableStreamSharing);
+ var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.EnableStreamSharing);
_liveStreamsSemaphore.Release();
return new Tuple<LiveStream, MediaSourceInfo, ITunerHost>(result, openedMediaSource, result.TunerHost);
}
@@ -885,7 +901,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
- var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, 0, result.EnableStreamSharing);
+ var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.EnableStreamSharing);
_liveStreams[openedMediaSource.Id] = result;
@@ -1542,6 +1558,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (timer.IsKids)
{
AddGenre(timer.Genres, "Kids");
+ AddGenre(timer.Genres, "Children");
}
if (timer.IsNews)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 72287f32d..fd9e75b6f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -223,8 +223,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return result.Items.FirstOrDefault();
}
- private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
-
public async Task<MediaSourceInfo> GetRecordingStream(string id, CancellationToken cancellationToken)
{
var info = await GetLiveStream(id, null, false, cancellationToken).ConfigureAwait(false);
@@ -284,80 +282,65 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStream(string id, string mediaSourceId, bool isChannel, CancellationToken cancellationToken)
{
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
if (string.Equals(id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
{
mediaSourceId = null;
}
- try
+ MediaSourceInfo info;
+ bool isVideo;
+ ILiveTvService service;
+ IDirectStreamProvider directStreamProvider = null;
+
+ if (isChannel)
{
- MediaSourceInfo info;
- bool isVideo;
- ILiveTvService service;
- IDirectStreamProvider directStreamProvider = null;
+ var channel = GetInternalChannel(id);
+ isVideo = channel.ChannelType == ChannelType.TV;
+ service = GetService(channel);
+ _logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
- if (isChannel)
+ var supportsManagedStream = service as ISupportsDirectStreamProvider;
+ if (supportsManagedStream != null)
{
- var channel = GetInternalChannel(id);
- isVideo = channel.ChannelType == ChannelType.TV;
- service = GetService(channel);
- _logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
-
- var supportsManagedStream = service as ISupportsDirectStreamProvider;
- if (supportsManagedStream != null)
- {
- var streamInfo = await supportsManagedStream.GetChannelStreamWithDirectStreamProvider(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false);
- info = streamInfo.Item1;
- directStreamProvider = streamInfo.Item2;
- }
- else
- {
- info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false);
- }
- info.RequiresClosing = true;
-
- if (info.RequiresClosing)
- {
- var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_";
-
- info.LiveStreamId = idPrefix + info.Id;
- }
+ var streamInfo = await supportsManagedStream.GetChannelStreamWithDirectStreamProvider(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false);
+ info = streamInfo.Item1;
+ directStreamProvider = streamInfo.Item2;
}
else
{
- var recording = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false);
- isVideo = !string.Equals(recording.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase);
- service = GetService(recording);
-
- _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.ExternalId);
- info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false);
- info.RequiresClosing = true;
-
- if (info.RequiresClosing)
- {
- var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_";
-
- info.LiveStreamId = idPrefix + info.Id;
- }
+ info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false);
}
+ info.RequiresClosing = true;
- _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
- Normalize(info, service, isVideo);
+ if (info.RequiresClosing)
+ {
+ var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_";
- return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info, directStreamProvider);
+ info.LiveStreamId = idPrefix + info.Id;
+ }
}
- catch (Exception ex)
+ else
{
- _logger.ErrorException("Error getting channel stream", ex);
+ var recording = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false);
+ isVideo = !string.Equals(recording.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase);
+ service = GetService(recording);
- throw;
- }
- finally
- {
- _liveStreamSemaphore.Release();
+ _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.ExternalId);
+ info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false);
+ info.RequiresClosing = true;
+
+ if (info.RequiresClosing)
+ {
+ var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_";
+
+ info.LiveStreamId = idPrefix + info.Id;
+ }
}
+
+ _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
+ Normalize(info, service, isVideo);
+
+ return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info, directStreamProvider);
}
private void Normalize(MediaSourceInfo mediaSource, ILiveTvService service, bool isVideo)
@@ -2560,35 +2543,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task CloseLiveStream(string id)
{
- await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- var parts = id.Split(new[] { '_' }, 2);
-
- var service = _services.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), parts[0], StringComparison.OrdinalIgnoreCase));
+ var parts = id.Split(new[] { '_' }, 2);
- if (service == null)
- {
- throw new ArgumentException("Service not found.");
- }
+ var service = _services.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), parts[0], StringComparison.OrdinalIgnoreCase));
- id = parts[1];
+ if (service == null)
+ {
+ throw new ArgumentException("Service not found.");
+ }
- _logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id);
+ id = parts[1];
- await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing live stream", ex);
+ _logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id);
- throw;
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
+ await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false);
}
public GuideInfo GetGuideInfo()
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index d77d0f33e..ff9b2a143 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -139,7 +140,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
try
{
- await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false);
+ if (stream.MediaStreams.Any(i => i.Index != -1))
+ {
+ await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+ }
}
catch (Exception ex)
{
@@ -208,10 +216,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
- private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{
var originalRuntime = mediaSource.RunTimeTicks;
+ var now = DateTime.UtcNow;
+
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
{
InputPath = mediaSource.Path,
@@ -221,6 +231,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}, cancellationToken).ConfigureAwait(false);
+ _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+
mediaSource.Bitrate = info.Bitrate;
mediaSource.Container = info.Container;
mediaSource.Formats = info.Formats;
@@ -272,6 +284,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
videoStream.BitRate = 1000000;
}
}
+
+ // This is coming up false and preventing stream copy
+ videoStream.IsAVC = null;
}
// Try to estimate this
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 84ba15e49..0fe74798f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -233,25 +233,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
- private async Task AddMediaInfo(LiveStream stream, bool isAudio, CancellationToken cancellationToken)
- {
- //await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- //try
- //{
- // await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
-
- // // Leave the resource locked. it will be released upstream
- //}
- //catch (Exception)
- //{
- // // Release the resource if there's some kind of failure.
- // resourcePool.Release();
-
- // throw;
- //}
- }
-
protected abstract bool IsValidChannelId(string channelId);
protected LiveTvOptions GetConfiguration()
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 101b9ba84..365f784a7 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
});
}
- private Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
+ private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
private async Task<string> GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken)
{
lock (_modelCache)
@@ -387,6 +387,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
id += "_" + url.GetMD5().ToString("N");
+ var enableLocalBuffer = EnableLocalBuffer();
+
var mediaSource = new MediaSourceInfo
{
Path = url,
@@ -420,8 +422,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BufferMs = 0,
Container = "ts",
Id = id,
- SupportsDirectPlay = false,
- SupportsDirectStream = true,
+ SupportsDirectPlay = !enableLocalBuffer,
+ SupportsDirectStream = enableLocalBuffer,
SupportsTranscoding = true,
IsInfiniteStream = true
};
@@ -488,6 +490,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
}
+ private bool EnableLocalBuffer()
+ {
+ return true;
+ }
+
protected override async Task<LiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
var profile = streamId.Split('_')[0];
@@ -502,25 +509,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var mediaSource = await GetMediaSource(info, hdhrId, profile).ConfigureAwait(false);
- var liveStream = new HdHomerunLiveStream(mediaSource, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
- if (info.AllowHWTranscoding)
+ if (EnableLocalBuffer())
{
- var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
-
- if ((model ?? string.Empty).IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
+ var liveStream = new HdHomerunLiveStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
+ if (info.AllowHWTranscoding)
{
- liveStream.EnableStreamSharing = !info.AllowHWTranscoding;
+ var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
+
+ if ((model ?? string.Empty).IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ liveStream.EnableStreamSharing = !info.AllowHWTranscoding;
+ }
+ else
+ {
+ liveStream.EnableStreamSharing = true;
+ }
}
else
{
liveStream.EnableStreamSharing = true;
}
+ return liveStream;
}
else
{
- liveStream.EnableStreamSharing = true;
+ var liveStream = new LiveStream(mediaSource);
+ liveStream.EnableStreamSharing = false;
+ return liveStream;
}
- return liveStream;
}
public async Task Validate(TunerHostInfo info)
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
index dd7726be0..60222415c 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
@@ -26,8 +27,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
+ private readonly MulticastStream _multicastStream;
- public HdHomerunLiveStream(MediaSourceInfo mediaSource, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
+
+ public HdHomerunLiveStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
: base(mediaSource)
{
_fileSystem = fileSystem;
@@ -35,6 +38,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_logger = logger;
_appPaths = appPaths;
_appHost = appHost;
+ OriginalStreamId = originalStreamId;
+ _multicastStream = new MulticastStream(_logger);
}
protected override async Task OpenInternal(CancellationToken openCancellationToken)
@@ -44,22 +49,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var mediaSource = OriginalMediaSource;
var url = mediaSource.Path;
- var tempFile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
- Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
-
- _logger.Info("Opening HDHR Live stream from {0} to {1}", url, tempFile);
- var output = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read);
+ _logger.Info("Opening HDHR Live stream from {0}", url);
var taskCompletionSource = new TaskCompletionSource<bool>();
- StartStreamingToTempFile(output, tempFile, url, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
+ StartStreaming(url, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile;
//OpenedMediaSource.ReadAtNativeFramerate = true;
- OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
+ OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
OpenedMediaSource.SupportsDirectPlay = false;
OpenedMediaSource.SupportsDirectStream = true;
@@ -78,178 +79,67 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task;
}
- private async Task StartStreamingToTempFile(Stream outputStream, string tempFilePath, string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+ private async Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
await Task.Run(async () =>
{
- using (outputStream)
- {
- var isFirstAttempt = true;
+ var isFirstAttempt = true;
- while (!cancellationToken.IsCancellationRequested)
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ try
{
- try
+ using (var response = await _httpClient.SendAsync(new HttpRequestOptions
{
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- BufferContent = false
+ Url = url,
+ CancellationToken = cancellationToken,
+ BufferContent = false
+
+ }, "GET").ConfigureAwait(false))
+ {
+ _logger.Info("Opened HDHR stream from {0}", url);
- }, "GET").ConfigureAwait(false))
+ if (!cancellationToken.IsCancellationRequested)
{
- _logger.Info("Opened HDHR stream from {0}", url);
+ _logger.Info("Beginning multicastStream.CopyUntilCancelled");
- if (!cancellationToken.IsCancellationRequested)
+ Action onStarted = null;
+ if (isFirstAttempt)
{
- _logger.Info("Beginning DirectRecorder.CopyUntilCancelled");
-
- Action onStarted = null;
- if (isFirstAttempt)
- {
- onStarted = () => ResolveWhenExists(openTaskCompletionSource, tempFilePath, cancellationToken);
- }
- await CopyUntilCancelled(response.Content, outputStream, onStarted, cancellationToken).ConfigureAwait(false);
+ onStarted = () => openTaskCompletionSource.TrySetResult(true);
}
- }
- }
- catch (OperationCanceledException)
- {
- break;
- }
- catch (Exception ex)
- {
- if (isFirstAttempt)
- {
- _logger.ErrorException("Error opening live stream:", ex);
- openTaskCompletionSource.TrySetException(ex);
- break;
- }
- _logger.ErrorException("Error copying live stream, will reopen", ex);
+ await _multicastStream.CopyUntilCancelled(response.Content, onStarted, cancellationToken).ConfigureAwait(false);
+ }
}
-
- isFirstAttempt = false;
}
- }
-
- _liveStreamTaskCompletionSource.TrySetResult(true);
-
- DeleteTempFile(tempFilePath);
-
- }).ConfigureAwait(false);
- }
-
- private readonly List<Tuple<Stream, CancellationToken, TaskCompletionSource<bool>>> _additionalStreams = new List<Tuple<Stream, CancellationToken, TaskCompletionSource<bool>>>();
-
- public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
- {
- var taskCompletionSource = new TaskCompletionSource<bool>();
- _additionalStreams.Add(new Tuple<Stream, CancellationToken, TaskCompletionSource<bool>>(stream, cancellationToken, taskCompletionSource));
-
- return taskCompletionSource.Task;
- }
-
- private void PopAdditionalStream(Tuple<Stream, CancellationToken, TaskCompletionSource<bool>> stream, Exception exception)
- {
- if (_additionalStreams.Remove(stream))
- {
- stream.Item3.TrySetException(exception);
- }
- }
-
- private const int BufferSize = 81920;
- private async Task CopyUntilCancelled(Stream source, Stream target, Action onStarted, CancellationToken cancellationToken)
- {
- while (!cancellationToken.IsCancellationRequested)
- {
- var bytesRead = await CopyToAsyncInternal(source, target, BufferSize, onStarted, cancellationToken).ConfigureAwait(false);
-
- onStarted = null;
-
- //var position = fs.Position;
- //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
-
- if (bytesRead == 0)
- {
- await Task.Delay(100).ConfigureAwait(false);
- }
- }
- }
-
- private async Task<int> CopyToAsyncInternal(Stream source, Stream destination, Int32 bufferSize, Action onStarted, CancellationToken cancellationToken)
- {
- byte[] buffer = new byte[bufferSize];
- int bytesRead;
- int totalBytesRead = 0;
-
- while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
- {
- await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
-
- var additionalStreams = _additionalStreams.ToList();
- foreach (var additionalStream in additionalStreams)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
+ catch (OperationCanceledException)
{
- await additionalStream.Item1.WriteAsync(buffer, 0, bytesRead, additionalStream.Item2).ConfigureAwait(false);
+ break;
}
catch (Exception ex)
{
- _logger.ErrorException("Error writing HDHR data to stream", ex);
+ if (isFirstAttempt)
+ {
+ _logger.ErrorException("Error opening live stream:", ex);
+ openTaskCompletionSource.TrySetException(ex);
+ break;
+ }
- PopAdditionalStream(additionalStream, ex);
+ _logger.ErrorException("Error copying live stream, will reopen", ex);
}
- }
- totalBytesRead += bytesRead;
-
- if (onStarted != null)
- {
- onStarted();
+ isFirstAttempt = false;
}
- onStarted = null;
- }
- return totalBytesRead;
- }
-
- private async void ResolveWhenExists(TaskCompletionSource<bool> taskCompletionSource, string file, CancellationToken cancellationToken)
- {
- while (!File.Exists(file) && !cancellationToken.IsCancellationRequested)
- {
- await Task.Delay(50).ConfigureAwait(false);
- }
+ _liveStreamTaskCompletionSource.TrySetResult(true);
- taskCompletionSource.TrySetResult(true);
+ }).ConfigureAwait(false);
}
- private async void DeleteTempFile(string path)
+ public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- for (var i = 0; i < 10; i++)
- {
- try
- {
- File.Delete(path);
- return;
- }
- catch (FileNotFoundException)
- {
- return;
- }
- catch (DirectoryNotFoundException)
- {
- return;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting temp file {0}", ex, path);
- }
-
- await Task.Delay(1000).ConfigureAwait(false);
- }
+ return _multicastStream.CopyToAsync(stream);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
new file mode 100644
index 000000000..8ff3fd6c1
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
+{
+ public class MulticastStream
+ {
+ private readonly List<QueueStream> _outputStreams = new List<QueueStream>();
+ private const int BufferSize = 81920;
+ private CancellationToken _cancellationToken;
+ private readonly ILogger _logger;
+
+ public MulticastStream(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
+ {
+ _cancellationToken = cancellationToken;
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ byte[] buffer = new byte[BufferSize];
+
+ var bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
+
+ if (bytesRead > 0)
+ {
+ byte[] copy = new byte[bytesRead];
+ Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
+
+ List<QueueStream> streams = null;
+
+ lock (_outputStreams)
+ {
+ streams = _outputStreams.ToList();
+ }
+
+ foreach (var stream in streams)
+ {
+ stream.Queue(copy);
+ }
+
+ if (onStarted != null)
+ {
+ var onStartedCopy = onStarted;
+ onStarted = null;
+ Task.Run(onStartedCopy);
+ }
+ }
+
+ else
+ {
+ await Task.Delay(100).ConfigureAwait(false);
+ }
+ }
+ }
+
+ public Task CopyToAsync(Stream stream)
+ {
+ var result = new QueueStream(stream, _logger)
+ {
+ OnFinished = OnFinished
+ };
+
+ lock (_outputStreams)
+ {
+ _outputStreams.Add(result);
+ }
+
+ result.Start(_cancellationToken);
+
+ return result.TaskCompletion.Task;
+ }
+
+ public void RemoveOutputStream(QueueStream stream)
+ {
+ lock (_outputStreams)
+ {
+ _outputStreams.Remove(stream);
+ }
+ }
+
+ private void OnFinished(QueueStream queueStream)
+ {
+ RemoveOutputStream(queueStream);
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
new file mode 100644
index 000000000..7bc53fa24
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
+{
+ public class QueueStream
+ {
+ private readonly Stream _outputStream;
+ private readonly ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();
+ private CancellationToken _cancellationToken;
+ public TaskCompletionSource<bool> TaskCompletion { get; private set; }
+
+ public Action<QueueStream> OnFinished { get; set; }
+ private readonly ILogger _logger;
+
+ public QueueStream(Stream outputStream, ILogger logger)
+ {
+ _outputStream = outputStream;
+ _logger = logger;
+ TaskCompletion = new TaskCompletionSource<bool>();
+ }
+
+ public void Queue(byte[] bytes)
+ {
+ _queue.Enqueue(bytes);
+ }
+
+ public void Start(CancellationToken cancellationToken)
+ {
+ _cancellationToken = cancellationToken;
+ Task.Run(StartInternal);
+ }
+
+ private byte[] Dequeue()
+ {
+ byte[] bytes;
+ if (_queue.TryDequeue(out bytes))
+ {
+ return bytes;
+ }
+
+ return null;
+ }
+
+ private async Task StartInternal()
+ {
+ var cancellationToken = _cancellationToken;
+
+ try
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ var bytes = Dequeue();
+ if (bytes != null)
+ {
+ await _outputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await Task.Delay(50, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ TaskCompletion.TrySetResult(true);
+ _logger.Debug("QueueStream complete");
+ }
+ catch (OperationCanceledException)
+ {
+ _logger.Debug("QueueStream cancelled");
+ TaskCompletion.TrySetCanceled();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in QueueStream", ex);
+ TaskCompletion.TrySetException(ex);
+ }
+ finally
+ {
+ if (OnFinished != null)
+ {
+ OnFinished(this);
+ }
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
index 5e2f98c09..bc0dc236d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
@@ -47,7 +47,6 @@
"NotificationOptionTaskFailed": "Scheduled task failure",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionServerRestartRequired": "Server restart required",
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 12691a69b..78b04aaa5 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -161,7 +161,6 @@
<Compile Include="HttpServer\HttpListenerHost.cs" />
<Compile Include="HttpServer\HttpResultFactory.cs" />
<Compile Include="HttpServer\LoggerUtils.cs" />
- <Compile Include="HttpServer\NativeWebSocket.cs" />
<Compile Include="HttpServer\RangeRequestWriter.cs" />
<Compile Include="HttpServer\ResponseFilter.cs" />
<Compile Include="HttpServer\Security\AuthService.cs" />
@@ -247,6 +246,8 @@
<Compile Include="LiveTv\ProgramImageProvider.cs" />
<Compile Include="LiveTv\RecordingImageProvider.cs" />
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
+ <Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
+ <Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\ChannelScan.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\ReportBlock.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpAppPacket.cs" />
diff --git a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
index 98d3672fa..8ca667739 100644
--- a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
@@ -91,13 +91,6 @@ namespace MediaBrowser.Server.Implementations.Notifications
new NotificationTypeInfo
{
- Type = NotificationType.NewLibraryContentMultiple.ToString(),
- DefaultTitle = "{ItemCount} new items have been added to your media library.",
- Variables = new List<string>{"ItemCount"}
- },
-
- new NotificationTypeInfo
- {
Type = NotificationType.AudioPlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index e8c1ce3fb..8a8d0b749 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
var cacheSize = _config.Configuration.SqliteCacheSize;
if (cacheSize <= 0)
{
- cacheSize = Math.Min(Environment.ProcessorCount * 50000, 200000);
+ cacheSize = Math.Min(Environment.ProcessorCount * 50000, 100000);
}
var connection = await DbConnector.Connect(DbFilePath, false, false, 0 - cacheSize).ConfigureAwait(false);
@@ -2656,6 +2656,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ if (query.SimilarTo != null)
+ {
+ whereClauses.Add("SimilarityScore > 0");
+ }
+
if (query.IsFolder.HasValue)
{
whereClauses.Add("IsFolder=@IsFolder");
diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
index af0699834..60b04cf82 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager
public class WebSocketConnection : IWebSocketConnection
{
public event EventHandler<EventArgs> Closed;
-
+
/// <summary>
/// The _socket
/// </summary>
@@ -37,11 +37,6 @@ namespace MediaBrowser.Server.Implementations.ServerManager
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
/// <summary>
- /// The _send semaphore
- /// </summary>
- private readonly SemaphoreSlim _sendSemaphore = new SemaphoreSlim(1, 1);
-
- /// <summary>
/// The logger
/// </summary>
private readonly ILogger _logger;
@@ -210,7 +205,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager
_logger.ErrorException("Error processing web socket message", ex);
}
}
-
+
/// <summary>
/// Sends a message asynchronously.
/// </summary>
@@ -237,7 +232,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <param name="buffer">The buffer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public async Task SendAsync(byte[] buffer, CancellationToken cancellationToken)
+ public Task SendAsync(byte[] buffer, CancellationToken cancellationToken)
{
if (buffer == null)
{
@@ -246,33 +241,10 @@ namespace MediaBrowser.Server.Implementations.ServerManager
cancellationToken.ThrowIfCancellationRequested();
- // Per msdn docs, attempting to send simultaneous messages will result in one failing.
- // This should help us workaround that and ensure all messages get sent
- await _sendSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- await _socket.SendAsync(buffer, true, cancellationToken);
- }
- catch (OperationCanceledException)
- {
- _logger.Info("WebSocket message to {0} was cancelled", RemoteEndPoint);
-
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error sending WebSocket message {0}", ex, RemoteEndPoint);
-
- throw;
- }
- finally
- {
- _sendSemaphore.Release();
- }
+ return _socket.SendAsync(buffer, true, cancellationToken);
}
- public async Task SendAsync(string text, CancellationToken cancellationToken)
+ public Task SendAsync(string text, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(text))
{
@@ -281,30 +253,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager
cancellationToken.ThrowIfCancellationRequested();
- // Per msdn docs, attempting to send simultaneous messages will result in one failing.
- // This should help us workaround that and ensure all messages get sent
- await _sendSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- await _socket.SendAsync(text, true, cancellationToken);
- }
- catch (OperationCanceledException)
- {
- _logger.Info("WebSocket message to {0} was cancelled", RemoteEndPoint);
-
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error sending WebSocket message {0}", ex, RemoteEndPoint);
-
- throw;
- }
- finally
- {
- _sendSemaphore.Release();
- }
+ return _socket.SendAsync(text, true, cancellationToken);
}
/// <summary>
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 18b340709..0ea50b39e 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -677,19 +677,11 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task{IUserRepository}.</returns>
private async Task<IUserRepository> GetUserRepository()
{
- try
- {
- var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector(), MemoryStreamProvider);
+ var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector(), MemoryStreamProvider);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
- return repo;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error opening user db", ex);
- throw;
- }
+ return repo;
}
/// <summary>
@@ -818,7 +810,6 @@ namespace MediaBrowser.Server.Startup.Common
GetExports<IMetadataService>(),
GetExports<IMetadataProvider>(),
GetExports<IMetadataSaver>(),
- GetExports<IImageSaver>(),
GetExports<IExternalId>());
ImageProcessor.AddParts(GetExports<IImageEnhancer>());
diff --git a/MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs b/MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs
deleted file mode 100644
index 01eeb5f3b..000000000
--- a/MediaBrowser.XbmcMetadata/Images/XbmcImageSaver.cs
+++ /dev/null
@@ -1,272 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.XbmcMetadata.Images
-{
- public class XbmcImageSaver : IImageFileSaver
- {
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index)
- {
- var season = item as Season;
-
- if (!SupportsItem(item, type, season))
- {
- return new string[] { };
- }
-
- var extension = "." + format.ToString().ToLower();
-
- // Backdrop paths
- if (type == ImageType.Backdrop)
- {
- if (index == 0)
- {
- if (item.IsInMixedFolder)
- {
- return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) };
- }
-
- if (season != null && season.IndexNumber.HasValue)
- {
- var seriesFolder = season.SeriesPath;
-
- var seasonMarker = season.IndexNumber.Value == 0
- ? "-specials"
- : season.IndexNumber.Value.ToString("00", _usCulture);
-
- var imageFilename = "season" + seasonMarker + "-fanart" + extension;
-
- return new[] { Path.Combine(seriesFolder, imageFilename) };
- }
-
- return new[]
- {
- Path.Combine(item.ContainingFolderPath, "fanart" + extension)
- };
- }
-
- if (item.IsInMixedFolder)
- {
- return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + index.ToString(_usCulture), extension) };
- }
-
- var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", index);
-
- return new[]
- {
- Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension),
- Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + index.ToString(_usCulture) + extension)
- };
- }
-
- if (type == ImageType.Primary)
- {
- if (season != null && season.IndexNumber.HasValue)
- {
- var seriesFolder = season.SeriesPath;
-
- var seasonMarker = season.IndexNumber.Value == 0
- ? "-specials"
- : season.IndexNumber.Value.ToString("00", _usCulture);
-
- var imageFilename = "season" + seasonMarker + "-poster" + extension;
-
- return new[] { Path.Combine(seriesFolder, imageFilename) };
- }
-
- if (item is Episode)
- {
- var seasonFolder = Path.GetDirectoryName(item.Path);
-
- var imageFilename = Path.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension;
-
- return new[] { Path.Combine(seasonFolder, imageFilename) };
- }
-
- if (item.IsInMixedFolder || item is MusicVideo)
- {
- return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) };
- }
-
- if (item is MusicAlbum || item is MusicArtist)
- {
- return new[] { Path.Combine(item.ContainingFolderPath, "folder" + extension) };
- }
-
- return new[] { Path.Combine(item.ContainingFolderPath, "poster" + extension) };
- }
-
- if (type == ImageType.Banner)
- {
- if (season != null && season.IndexNumber.HasValue)
- {
- var seriesFolder = season.SeriesPath;
-
- var seasonMarker = season.IndexNumber.Value == 0
- ? "-specials"
- : season.IndexNumber.Value.ToString("00", _usCulture);
-
- var imageFilename = "season" + seasonMarker + "-banner" + extension;
-
- return new[] { Path.Combine(seriesFolder, imageFilename) };
- }
- }
-
- if (type == ImageType.Thumb)
- {
- if (season != null && season.IndexNumber.HasValue)
- {
- var seriesFolder = season.SeriesPath;
-
- var seasonMarker = season.IndexNumber.Value == 0
- ? "-specials"
- : season.IndexNumber.Value.ToString("00", _usCulture);
-
- var imageFilename = "season" + seasonMarker + "-landscape" + extension;
-
- return new[] { Path.Combine(seriesFolder, imageFilename) };
- }
-
- if (item.IsInMixedFolder)
- {
- return new[] { GetSavePathForItemInMixedFolder(item, type, "landscape", extension) };
- }
-
- return new[] { Path.Combine(item.ContainingFolderPath, "landscape" + extension) };
- }
-
- return GetStandardSavePaths(item, type, index, extension);
- }
-
- private IEnumerable<string> GetStandardSavePaths(IHasImages item, ImageType type, int imageIndex, string extension)
- {
- string filename;
-
- switch (type)
- {
- case ImageType.Art:
- filename = "clearart";
- break;
- case ImageType.BoxRear:
- filename = "back";
- break;
- case ImageType.Disc:
- filename = item is MusicAlbum ? "cdart" : "disc";
- break;
- case ImageType.Screenshot:
- filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex);
- break;
- default:
- filename = type.ToString().ToLower();
- break;
- }
-
- string path = null;
-
- if (item.IsInMixedFolder)
- {
- path = GetSavePathForItemInMixedFolder(item, type, filename, extension);
- }
-
- if (string.IsNullOrEmpty(path))
- {
- path = Path.Combine(item.ContainingFolderPath, filename + extension);
- }
-
- if (string.IsNullOrEmpty(path))
- {
- return new string[] { };
- }
-
- return new[] { path };
- }
-
-
- private string GetSavePathForItemInMixedFolder(IHasImages item, ImageType type, string imageFilename, string extension)
- {
- if (type == ImageType.Primary)
- {
- imageFilename = "poster";
- }
- var folder = Path.GetDirectoryName(item.Path);
-
- return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension);
- }
-
- private bool SupportsItem(IHasImages item, ImageType type, Season season)
- {
- if (item.IsOwnedItem || item is Audio || item is User)
- {
- return false;
- }
-
- if (type != ImageType.Primary && item is Episode)
- {
- return false;
- }
-
- if (!item.SupportsLocalMetadata)
- {
- return false;
- }
-
- var locationType = item.LocationType;
- if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
- {
- var allowSaving = false;
-
- // If season is virtual under a physical series, save locally if using compatible convention
- if (season != null)
- {
- var series = season.Series;
-
- if (series != null && series.SupportsLocalMetadata)
- {
- allowSaving = true;
- }
- }
-
- if (!allowSaving)
- {
- return false;
- }
- }
-
- return true;
- }
-
- private string GetBackdropSaveFilename(IEnumerable<ItemImageInfo> images, string zeroIndexFilename, string numberedIndexPrefix, int? index)
- {
- if (index.HasValue && index.Value == 0)
- {
- return zeroIndexFilename;
- }
-
- var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList();
-
- var current = 1;
- while (filenames.Contains(numberedIndexPrefix + current.ToString(_usCulture), StringComparer.OrdinalIgnoreCase))
- {
- current++;
- }
-
- return numberedIndexPrefix + current.ToString(_usCulture);
- }
-
- public string Name
- {
- get { return "Emby/Plex/Xbmc Images"; }
- }
- }
-}
diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
index d95d8f12d..f3147a065 100644
--- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
+++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
@@ -52,7 +52,6 @@
</Compile>
<Compile Include="Configuration\NfoOptions.cs" />
<Compile Include="EntryPoint.cs" />
- <Compile Include="Images\XbmcImageSaver.cs" />
<Compile Include="Parsers\BaseNfoParser.cs" />
<Compile Include="Parsers\EpisodeNfoParser.cs" />
<Compile Include="Parsers\MovieNfoParser.cs" />