aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Drawing/Emby.Drawing.csproj1
-rw-r--r--Emby.Drawing/ImageMagick/ImageMagickEncoder.cs17
-rw-r--r--Emby.Drawing/ImageMagick/StripCollageBuilder.cs351
-rw-r--r--MediaBrowser.Api/BaseApiService.cs2
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs20
-rw-r--r--MediaBrowser.Api/GamesService.cs9
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs10
-rw-r--r--MediaBrowser.Api/Images/RemoteImageService.cs10
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs49
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs5
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs6
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs154
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs18
-rw-r--r--MediaBrowser.Api/Music/AlbumsService.cs13
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs21
-rw-r--r--MediaBrowser.Api/PackageReviewService.cs12
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs4
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs9
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs5
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs28
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs5
-rw-r--r--MediaBrowser.Api/PlaylistService.cs4
-rw-r--r--MediaBrowser.Api/SimilarItemsHelper.cs12
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs15
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs10
-rw-r--r--MediaBrowser.Api/Sync/SyncService.cs19
-rw-r--r--MediaBrowser.Api/System/SystemInfoWebSocketListener.cs2
-rw-r--r--MediaBrowser.Api/System/SystemService.cs16
-rw-r--r--MediaBrowser.Api/TvShowsService.cs25
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs40
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs134
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs25
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs61
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs18
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs17
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs11
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs12
-rw-r--r--MediaBrowser.Api/UserService.cs9
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs10
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs3
-rw-r--r--MediaBrowser.Controller/Channels/ChannelItemInfo.cs8
-rw-r--r--MediaBrowser.Controller/Chapters/IChapterManager.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageCollageOptions.cs5
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs19
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs11
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs105
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs11
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs3
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs11
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs32
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs102
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs7
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs32
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs3
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs7
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs15
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs4
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs11
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs19
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerEventInfo.cs14
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs10
-rw-r--r--MediaBrowser.Controller/Net/IHttpResultFactory.cs8
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs14
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs8
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs3
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs22
-rw-r--r--MediaBrowser.Dlna/Main/DlnaEntryPoint.cs13
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs35
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs2
-rw-r--r--MediaBrowser.Dlna/Profiles/LgTvProfile.cs15
-rw-r--r--MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml2
-rw-r--r--MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs29
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs141
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs4
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj6
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj6
-rw-r--r--MediaBrowser.Model/Channels/ChannelFolderType.cs8
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs1
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs10
-rw-r--r--MediaBrowser.Model/Dlna/ResolutionNormalizer.cs20
-rw-r--r--MediaBrowser.Model/Dto/ItemCounts.cs1
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs26
-rw-r--r--MediaBrowser.Model/Entities/MediaUrl.cs1
-rw-r--r--MediaBrowser.Model/Entities/VideoSize.cs8
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs30
-rw-r--r--MediaBrowser.Model/LiveTv/RecordingQuery.cs7
-rw-r--r--MediaBrowser.Model/LiveTv/TimerQuery.cs2
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj2
-rw-r--r--MediaBrowser.Model/Querying/ItemSortBy.cs1
-rw-r--r--MediaBrowser.Model/System/Architecture.cs9
-rw-r--r--MediaBrowser.Model/System/SystemInfo.cs4
-rw-r--r--MediaBrowser.Providers/Chapters/ChapterManager.cs2
-rw-r--r--MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs3
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbSearch.cs24
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs195
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs11
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbProvider.cs200
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs22
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs5
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs39
-rw-r--r--MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs255
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs36
-rw-r--r--MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Connect/Responses.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs168
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs50
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs36
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs83
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs10
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs4
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs4
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs16
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs17
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs2
-rw-r--r--MediaBrowser.Server.Implementations/IO/FileRefresher.cs11
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs134
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs37
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs78
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs116
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs32
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs165
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs44
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs200
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs127
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs2
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj173
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs450
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs31
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs24
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs64
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs263
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs35
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs434
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs730
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs47
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs204
-rw-r--r--MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs332
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs42
-rw-r--r--MediaBrowser.Server.Implementations/Social/SharingManager.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Social/SharingRepository.cs174
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncRepository.cs868
-rw-r--r--MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs104
-rw-r--r--MediaBrowser.Server.Implementations/Udp/UdpServer.cs12
-rw-r--r--MediaBrowser.Server.Implementations/packages.config4
-rw-r--r--MediaBrowser.Server.Mac/Emby.Server.Mac.csproj3405
-rw-r--r--MediaBrowser.Server.Mac/Main.cs2
-rw-r--r--MediaBrowser.Server.Mac/Native/BaseMonoApp.cs28
-rw-r--r--MediaBrowser.Server.Mac/Native/NativeApp.cs8
-rw-r--r--MediaBrowser.Server.Mac/Native/SqliteExtensions.cs62
-rw-r--r--MediaBrowser.Server.Mono/Native/BaseMonoApp.cs9
-rw-r--r--MediaBrowser.Server.Mono/Native/DbConnector.cs4
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs204
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegInstallInfo.cs1
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs44
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs9
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj2
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs44
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs44
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs20
-rw-r--r--MediaBrowser.Server.Startup.Common/NativeEnvironment.cs10
-rw-r--r--MediaBrowser.ServerApplication/App.config1
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs90
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj8
-rw-r--r--MediaBrowser.ServerApplication/Native/DbConnector.cs13
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsApp.cs30
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs14
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs13
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj33
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs7
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec2
203 files changed, 6095 insertions, 6422 deletions
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
index dc410c321..aa7dc5a15 100644
--- a/Emby.Drawing/Emby.Drawing.csproj
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -80,7 +80,6 @@
<Compile Include="ImageMagick\UnplayedCountIndicator.cs" />
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="ImageMagick\fonts\MontserratLight.otf" />
<EmbeddedResource Include="ImageMagick\fonts\robotoregular.ttf" />
</ItemGroup>
<ItemGroup>
diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
index cb60d1123..3dbe7239d 100644
--- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
@@ -111,7 +111,6 @@ namespace Emby.Drawing.ImageMagick
wand.CurrentImage.TrimImage(10);
wand.SaveImage(outputPath);
}
- SaveDelay();
}
public ImageSize GetImageSize(string path)
@@ -189,7 +188,6 @@ namespace Emby.Drawing.ImageMagick
}
}
}
- SaveDelay();
}
private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options)
@@ -284,25 +282,16 @@ namespace Emby.Drawing.ImageMagick
if (ratio >= 1.4)
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
else if (ratio >= .9)
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
else
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
}
-
- SaveDelay();
- }
-
- private void SaveDelay()
- {
- // For some reason the images are not always getting released right away
- //var task = Task.Delay(300);
- //Task.WaitAll(task);
}
public string Name
diff --git a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
index c9e291a5e..7bc144c11 100644
--- a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
+++ b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
@@ -9,140 +9,35 @@ namespace Emby.Drawing.ImageMagick
public class StripCollageBuilder
{
private readonly IApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
+ private readonly IFileSystem _fileSystem;
- public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
+ public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
- _fileSystem = fileSystem;
+ _fileSystem = fileSystem;
}
- public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height, string text)
+ public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height)
{
- if (!string.IsNullOrWhiteSpace(text))
+ using (var wand = BuildPosterCollageWand(paths, width, height))
{
- using (var wand = BuildPosterCollageWandWithText(paths, text, width, height))
- {
- wand.SaveImage(outputPath);
- }
- }
- else
- {
- using (var wand = BuildPosterCollageWand(paths, width, height))
- {
- wand.SaveImage(outputPath);
- }
+ wand.SaveImage(outputPath);
}
}
- public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height, string text)
+ public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height)
{
- if (!string.IsNullOrWhiteSpace(text))
+ using (var wand = BuildSquareCollageWand(paths, width, height))
{
- using (var wand = BuildSquareCollageWandWithText(paths, text, width, height))
- {
- wand.SaveImage(outputPath);
- }
- }
- else
- {
- using (var wand = BuildSquareCollageWand(paths, width, height))
- {
- wand.SaveImage(outputPath);
- }
+ wand.SaveImage(outputPath);
}
}
- public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height, string text)
+ public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height)
{
- if (!string.IsNullOrWhiteSpace(text))
+ using (var wand = BuildThumbCollageWand(paths, width, height))
{
- using (var wand = BuildThumbCollageWandWithText(paths, text, width, height))
- {
- wand.SaveImage(outputPath);
- }
- }
- else
- {
- using (var wand = BuildThumbCollageWand(paths, width, height))
- {
- wand.SaveImage(outputPath);
- }
- }
- }
-
- private MagickWand BuildThumbCollageWandWithText(List<string> paths, string text, int width, int height)
- {
- var inputPaths = ImageHelpers.ProjectPaths(paths, 8);
- using (var wandImages = new MagickWand(inputPaths.ToArray()))
- {
- var wand = new MagickWand(width, height);
- wand.OpenImage("gradient:#111111-#111111");
- using (var draw = new DrawingWand())
- {
- using (var fcolor = new PixelWand(ColorName.White))
- {
- draw.FillColor = fcolor;
- draw.Font = MontserratLightFont;
- draw.FontSize = 60;
- draw.FontWeight = FontWeightType.LightStyle;
- draw.TextAntialias = true;
- }
-
- var fontMetrics = wand.QueryFontMetrics(draw, text);
- var textContainerY = Convert.ToInt32(height * .165);
- wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, text);
-
- var iSlice = Convert.ToInt32(width * .1166666667);
- int iTrans = Convert.ToInt32(height * 0.2);
- int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
- var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
-
- foreach (var element in wandImages.ImageList)
- {
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = new PixelWand("none", 1);
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
- }
-
- wandImages.SetFirstIterator();
- using (var wandList = wandImages.AppendImages())
- {
- wandList.CurrentImage.TrimImage(1);
- using (var mwr = wandList.CloneMagickWand())
- {
- using (var blackPixelWand = new PixelWand(ColorName.Black))
- {
- using (var greyPixelWand = new PixelWand(ColorName.Grey70))
- {
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
- {
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
- }
- }
- }
- }
- }
- }
-
- return wand;
+ wand.SaveImage(outputPath);
}
}
@@ -211,81 +106,6 @@ namespace Emby.Drawing.ImageMagick
}
}
- private MagickWand BuildPosterCollageWandWithText(List<string> paths, string label, int width, int height)
- {
- var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
- using (var wandImages = new MagickWand(inputPaths.ToArray()))
- {
- var wand = new MagickWand(width, height);
- wand.OpenImage("gradient:#111111-#111111");
- using (var draw = new DrawingWand())
- {
- using (var fcolor = new PixelWand(ColorName.White))
- {
- draw.FillColor = fcolor;
- draw.Font = MontserratLightFont;
- draw.FontSize = 60;
- draw.FontWeight = FontWeightType.LightStyle;
- draw.TextAntialias = true;
- }
-
- var fontMetrics = wand.QueryFontMetrics(draw, label);
- var textContainerY = Convert.ToInt32(height * .165);
- wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label);
-
- var iSlice = Convert.ToInt32(width * 0.225);
- int iTrans = Convert.ToInt32(height * 0.2);
- int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
- var horizontalImagePadding = Convert.ToInt32(width * 0.0275);
-
- foreach (var element in wandImages.ImageList)
- {
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = new PixelWand("none", 1);
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
- }
-
- wandImages.SetFirstIterator();
- using (var wandList = wandImages.AppendImages())
- {
- wandList.CurrentImage.TrimImage(1);
- using (var mwr = wandList.CloneMagickWand())
- {
- using (var blackPixelWand = new PixelWand(ColorName.Black))
- {
- using (var greyPixelWand = new PixelWand(ColorName.Grey70))
- {
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
- {
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
- }
- }
- }
- }
- }
- }
-
- return wand;
- }
- }
-
private MagickWand BuildThumbCollageWand(List<string> paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
@@ -353,147 +173,28 @@ namespace Emby.Drawing.ImageMagick
private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height)
{
- var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
- using (var wandImages = new MagickWand(inputPaths.ToArray()))
- {
- var wand = new MagickWand(width, height);
- wand.OpenImage("gradient:#111111-#111111");
- using (var draw = new DrawingWand())
- {
- var iSlice = Convert.ToInt32(width * .32);
- int iTrans = Convert.ToInt32(height * .25);
- int iHeight = Convert.ToInt32(height * .68);
- var horizontalImagePadding = Convert.ToInt32(width * 0.02);
-
- foreach (var element in wandImages.ImageList)
- {
- using (var blackPixelWand = new PixelWand(ColorName.Black))
- {
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = blackPixelWand;
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
- }
- }
-
- wandImages.SetFirstIterator();
- using (var wandList = wandImages.AppendImages())
- {
- wandList.CurrentImage.TrimImage(1);
- using (var mwr = wandList.CloneMagickWand())
- {
- using (var blackPixelWand = new PixelWand(ColorName.Black))
- {
- using (var greyPixelWand = new PixelWand(ColorName.Grey70))
- {
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
- {
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .03));
- }
- }
- }
- }
- }
- }
-
- return wand;
- }
- }
-
- private MagickWand BuildSquareCollageWandWithText(List<string> paths, string label, int width, int height)
- {
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
- using (var wandImages = new MagickWand(inputPaths.ToArray()))
+ var outputWand = new MagickWand(width, height, new PixelWand("none", 1));
+ var imageIndex = 0;
+ var cellWidth = width/2;
+ var cellHeight = height/2;
+ for (var x = 0; x < 2; x++)
{
- var wand = new MagickWand(width, height);
- wand.OpenImage("gradient:#111111-#111111");
- using (var draw = new DrawingWand())
+ for (var y = 0; y < 2; y++)
{
- using (var fcolor = new PixelWand(ColorName.White))
- {
- draw.FillColor = fcolor;
- draw.Font = MontserratLightFont;
- draw.FontSize = 60;
- draw.FontWeight = FontWeightType.LightStyle;
- draw.TextAntialias = true;
- }
-
- var fontMetrics = wand.QueryFontMetrics(draw, label);
- var textContainerY = Convert.ToInt32(height * .165);
- wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label);
-
- var iSlice = Convert.ToInt32(width * .225);
- int iTrans = Convert.ToInt32(height * 0.2);
- int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
- var horizontalImagePadding = Convert.ToInt32(width * 0.02);
-
- foreach (var element in wandImages.ImageList)
- {
- int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
- element.Gravity = GravityType.CenterGravity;
- element.BackgroundColor = new PixelWand("none", 1);
- element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
- int ix = (int)Math.Abs((iWidth - iSlice) / 2);
- element.CropImage(iSlice, iHeight, ix, 0);
-
- element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
- }
-
- wandImages.SetFirstIterator();
- using (var wandList = wandImages.AppendImages())
+ using (var temp = new MagickWand(inputPaths[imageIndex]))
{
- wandList.CurrentImage.TrimImage(1);
- using (var mwr = wandList.CloneMagickWand())
- {
- using (var blackPixelWand = new PixelWand(ColorName.Black))
- {
- using (var greyPixelWand = new PixelWand(ColorName.Grey70))
- {
- mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
- mwr.CurrentImage.FlipImage();
-
- mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
- mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
-
- using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
- {
- mwg.OpenImage("gradient:black-none");
- var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
- mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
-
- wandList.AddImage(mwr);
- int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
- wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
- }
- }
- }
- }
+ temp.CurrentImage.ScaleImage(cellWidth, cellHeight);
+ // draw this image into the strip at the next position
+ var xPos = x*cellWidth;
+ var yPos = y*cellHeight;
+ outputWand.CurrentImage.CompositeImage(temp, CompositeOperator.OverCompositeOp, xPos, yPos);
}
+ imageIndex++;
}
-
- return wand;
}
- }
- private string MontserratLightFont
- {
- get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths, _fileSystem); }
+ return outputWand;
}
}
}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 44d459a01..44a367be0 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -115,7 +115,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
protected object ToStaticFileResult(string path)
{
- return ResultFactory.GetStaticFileResult(Request, path);
+ return ResultFactory.GetStaticFileResult(Request, path).Result;
}
protected DtoOptions GetDtoOptions(object request)
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 446415fbb..9c8120de7 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -9,7 +9,9 @@ using ServiceStack.Web;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Api
{
@@ -71,6 +73,14 @@ namespace MediaBrowser.Api
}
+ [Route("/System/MediaEncoder/Path", "POST", Summary = "Updates the path to the media encoder")]
+ [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)]
+ public class UpdateMediaEncoderPath : IReturnVoid
+ {
+ [ApiMember(Name = "Path", Description = "Path", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Path { get; set; }
+ }
+
public class ConfigurationService : BaseApiService
{
/// <summary>
@@ -86,14 +96,22 @@ namespace MediaBrowser.Api
private readonly IFileSystem _fileSystem;
private readonly IProviderManager _providerManager;
private readonly ILibraryManager _libraryManager;
+ private readonly IMediaEncoder _mediaEncoder;
- public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager)
+ public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
{
_jsonSerializer = jsonSerializer;
_configurationManager = configurationManager;
_fileSystem = fileSystem;
_providerManager = providerManager;
_libraryManager = libraryManager;
+ _mediaEncoder = mediaEncoder;
+ }
+
+ public void Post(UpdateMediaEncoderPath request)
+ {
+ var task = _mediaEncoder.UpdateEncoderPath(request.Path);
+ Task.WaitAll(task);
}
/// <summary>
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index cb77e62ad..4758b0186 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api
@@ -186,14 +187,14 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetSimilarGames request)
+ public async Task<object> Get(GetSimilarGames request)
{
- var result = GetSimilarItemsResult(request);
+ var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
- private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -216,7 +217,7 @@ namespace MediaBrowser.Api
var result = new QueryResult<BaseItemDto>
{
- Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
+ Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = itemsResult.Count
};
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index e5fe5bd68..a511f8c72 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -514,7 +514,7 @@ namespace MediaBrowser.Api.Images
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>System.Object.</returns>
/// <exception cref="ResourceNotFoundException"></exception>
- public object GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
+ public Task<object> GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
{
if (request.PercentPlayed.HasValue)
{
@@ -594,8 +594,7 @@ namespace MediaBrowser.Api.Images
supportedImageEnhancers,
cacheDuration,
responseHeaders,
- isHeadRequest)
- .Result;
+ isHeadRequest);
}
private async Task<object> GetImageResult(IHasImages item,
@@ -632,7 +631,7 @@ namespace MediaBrowser.Api.Images
headers["Vary"] = "Accept";
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
CacheDuration = cacheDuration,
ResponseHeaders = headers,
@@ -643,7 +642,8 @@ namespace MediaBrowser.Api.Images
// Sometimes imagemagick keeps a hold on the file briefly even after it's done writing to it.
// I'd rather do this than add a delay after saving the file
FileShare = FileShare.ReadWrite
- });
+
+ }).ConfigureAwait(false);
}
private List<ImageFormat> GetOutputFormats(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List<IImageEnhancer> enhancers)
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
index 02d1cdbe2..b21e54495 100644
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ b/MediaBrowser.Api/Images/RemoteImageService.cs
@@ -238,9 +238,9 @@ namespace MediaBrowser.Api.Images
}
if (_fileSystem.FileExists(contentPath))
- {
- return ToStaticFileResult(contentPath);
- }
+ {
+ return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
+ }
}
catch (DirectoryNotFoundException)
{
@@ -259,9 +259,9 @@ namespace MediaBrowser.Api.Images
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
- return ToStaticFileResult(contentPath);
+ return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
-
+
/// <summary>
/// Downloads the image.
/// </summary>
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index 41bfd9da2..357ff4394 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -38,6 +38,12 @@ namespace MediaBrowser.Api
{
}
+ [Route("/Items/RemoteSearch/Trailer", "POST")]
+ [Authenticated]
+ public class GetTrailerRemoteSearchResults : RemoteSearchQuery<TrailerInfo>, IReturn<List<RemoteSearchResult>>
+ {
+ }
+
[Route("/Items/RemoteSearch/AdultVideo", "POST")]
[Authenticated]
public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery<ItemLookupInfo>, IReturn<List<RemoteSearchResult>>
@@ -132,60 +138,65 @@ namespace MediaBrowser.Api
return ToOptimizedResult(infos);
}
- public object Post(GetMovieRemoteSearchResults request)
+ public async Task<object> Post(GetTrailerRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<Trailer, TrailerInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetSeriesRemoteSearchResults request)
+ public async Task<object> Post(GetMovieRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetGameRemoteSearchResults request)
+ public async Task<object> Post(GetSeriesRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetBoxSetRemoteSearchResults request)
+ public async Task<object> Post(GetGameRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetPersonRemoteSearchResults request)
+ public async Task<object> Post(GetBoxSetRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetMusicAlbumRemoteSearchResults request)
+ public async Task<object> Post(GetPersonRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Post(GetMusicArtistRemoteSearchResults request)
+ public async Task<object> Post(GetMusicAlbumRemoteSearchResults request)
{
- var result = _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(request, CancellationToken.None).Result;
+ var result = await _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(request, CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Get(GetRemoteSearchImage request)
+ public async Task<object> Post(GetMusicArtistRemoteSearchResults request)
{
- var result = GetRemoteImage(request).Result;
+ var result = await _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(request, CancellationToken.None).ConfigureAwait(false);
- return result;
+ return ToOptimizedResult(result);
+ }
+
+ public Task<object> Get(GetRemoteSearchImage request)
+ {
+ return GetRemoteImage(request);
}
public void Post(ApplySearchCriteria request)
@@ -241,7 +252,7 @@ namespace MediaBrowser.Api
if (_fileSystem.FileExists(contentPath))
{
- return ToStaticFileResult(contentPath);
+ return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
}
catch (DirectoryNotFoundException)
@@ -261,7 +272,7 @@ namespace MediaBrowser.Api
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
- return ToStaticFileResult(contentPath);
+ return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false);
}
/// <summary>
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 6cb23a140..79aaccfe8 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -419,11 +419,6 @@ namespace MediaBrowser.Api
series.Status = request.SeriesStatus;
series.AirDays = request.AirDays;
series.AirTime = request.AirTime;
-
- if (request.DisplaySpecialsWithSeasons.HasValue)
- {
- series.DisplaySpecialsWithSeasons = request.DisplaySpecialsWithSeasons.Value;
- }
}
}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index f9b3def97..4cd6a66ef 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -493,7 +493,7 @@ namespace MediaBrowser.Api.Library
}
}
- public object Get(GetDownload request)
+ public Task<object> Get(GetDownload request)
{
var item = _libraryManager.GetItemById(request.Id);
var auth = _authContext.GetAuthorizationInfo(Request);
@@ -552,7 +552,7 @@ namespace MediaBrowser.Api.Library
}
}
- public object Get(GetFile request)
+ public Task<object> Get(GetFile request)
{
var item = _libraryManager.GetItemById(request.Id);
var locationType = item.LocationType;
@@ -565,7 +565,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentException("This command cannot be used for directories.");
}
- return ToStaticFileResult(item.Path);
+ return ResultFactory.GetStaticFileResult(Request, item.Path);
}
/// <summary>
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index d5290959d..784057b32 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -146,6 +146,13 @@ namespace MediaBrowser.Api.LiveTv
/// <value>The fields.</value>
[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; }
+
+ public GetRecordings()
+ {
+ EnableTotalRecordCount = true;
+ }
}
[Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
@@ -200,6 +207,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "SeriesTimerId", Description = "Optional filter by timers belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SeriesTimerId { get; set; }
+
+ public bool? IsActive { get; set; }
}
[Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
@@ -484,6 +493,40 @@ namespace MediaBrowser.Api.LiveTv
{
}
+ [Route("/LiveTv/ChannelMappingOptions")]
+ [Authenticated(AllowBeforeStartupWizard = true)]
+ public class GetChannelMappingOptions
+ {
+ [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ProviderId { get; set; }
+ }
+
+ [Route("/LiveTv/ChannelMappings")]
+ [Authenticated(AllowBeforeStartupWizard = true)]
+ public class SetChannelMapping
+ {
+ [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string ProviderId { get; set; }
+ public string TunerChannelNumber { get; set; }
+ public string ProviderChannelNumber { get; set; }
+ }
+
+ public class ChannelMappingOptions
+ {
+ public List<TunerChannelMapping> TunerChannels { get; set; }
+ public List<NameIdPair> ProviderChannels { get; set; }
+ public List<NameValuePair> Mappings { get; set; }
+ public string ProviderName { get; set; }
+ }
+
+ public class TunerChannelMapping
+ {
+ public string Name { get; set; }
+ public string Number { get; set; }
+ public string ProviderChannelNumber { get; set; }
+ public string ProviderChannelName { get; set; }
+ }
+
[Route("/LiveTv/Registration", "GET")]
[Authenticated]
public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord>
@@ -550,6 +593,102 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
+ public async Task<object> Post(SetChannelMapping request)
+ {
+ var config = GetConfiguration();
+
+ var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
+ listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase)).ToArray();
+
+ if (!string.Equals(request.TunerChannelNumber, request.ProviderChannelNumber, StringComparison.OrdinalIgnoreCase))
+ {
+ var list = listingsProviderInfo.ChannelMappings.ToList();
+ list.Add(new NameValuePair
+ {
+ Name = request.TunerChannelNumber,
+ Value = request.ProviderChannelNumber
+ });
+ listingsProviderInfo.ChannelMappings = list.ToArray();
+ }
+
+ UpdateConfiguration(config);
+
+ var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var mappings = listingsProviderInfo.ChannelMappings.ToList();
+
+ var tunerChannelMappings =
+ tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList();
+
+ return tunerChannelMappings.First(i => string.Equals(i.Number, request.TunerChannelNumber, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public async Task<object> Get(GetChannelMappingOptions request)
+ {
+ var config = GetConfiguration();
+
+ var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase));
+
+ var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name;
+
+ var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ var mappings = listingsProviderInfo.ChannelMappings.ToList();
+
+ var result = new ChannelMappingOptions
+ {
+ TunerChannels = tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(),
+
+ ProviderChannels = providerChannels.Select(i => new NameIdPair
+ {
+ Name = i.Name,
+ Id = i.Number
+
+ }).ToList(),
+
+ Mappings = mappings,
+
+ ProviderName = listingsProviderName
+ };
+
+ return ToOptimizedResult(result);
+ }
+
+ private TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List<NameValuePair> mappings, List<ChannelInfo> providerChannels)
+ {
+ var result = new TunerChannelMapping
+ {
+ Name = channel.Number + " " + channel.Name,
+ Number = channel.Number
+ };
+
+ var mapping = mappings.FirstOrDefault(i => string.Equals(i.Name, channel.Number, StringComparison.OrdinalIgnoreCase));
+ var providerChannelNumber = channel.Number;
+
+ if (mapping != null)
+ {
+ providerChannelNumber = mapping.Value;
+ }
+
+ var providerChannel = providerChannels.FirstOrDefault(i => string.Equals(i.Number, providerChannelNumber, StringComparison.OrdinalIgnoreCase));
+
+ if (providerChannel != null)
+ {
+ result.ProviderChannelNumber = providerChannel.Number;
+ result.ProviderChannelName = providerChannel.Name;
+ }
+
+ return result;
+ }
+
public object Get(GetSatIniMappings request)
{
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
@@ -618,6 +757,11 @@ namespace MediaBrowser.Api.LiveTv
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
+ private void UpdateConfiguration(LiveTvOptions options)
+ {
+ _config.SaveConfiguration("livetv", options);
+ }
+
public async Task<object> Get(GetLineups request)
{
var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false);
@@ -650,14 +794,14 @@ namespace MediaBrowser.Api.LiveTv
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
- var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ToArray();
+ var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
{
Items = returnArray,
TotalRecordCount = channelResult.TotalRecordCount
};
-
+
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -761,7 +905,8 @@ namespace MediaBrowser.Api.LiveTv
Limit = request.Limit,
Status = request.Status,
SeriesTimerId = request.SeriesTimerId,
- IsInProgress = request.IsInProgress
+ IsInProgress = request.IsInProgress,
+ EnableTotalRecordCount = request.EnableTotalRecordCount
}, options, CancellationToken.None).ConfigureAwait(false);
@@ -792,7 +937,8 @@ namespace MediaBrowser.Api.LiveTv
var result = await _liveTvManager.GetTimers(new TimerQuery
{
ChannelId = request.ChannelId,
- SeriesTimerId = request.SeriesTimerId
+ SeriesTimerId = request.SeriesTimerId,
+ IsActive = request.IsActive
}, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index ff18d440c..a2a935b12 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -111,16 +111,16 @@ namespace MediaBrowser.Api.Movies
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetSimilarMovies request)
+ public async Task<object> Get(GetSimilarMovies request)
{
- var result = GetSimilarItemsResult(request);
+ var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
- public object Get(GetSimilarTrailers request)
+ public async Task<object> Get(GetSimilarTrailers request)
{
- var result = GetSimilarItemsResult(request);
+ var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -138,7 +138,7 @@ namespace MediaBrowser.Api.Movies
return ToOptimizedResult(result);
}
- private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -163,7 +163,7 @@ namespace MediaBrowser.Api.Movies
var result = new QueryResult<BaseItemDto>
{
- Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
+ Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = itemsResult.Count
};
@@ -296,7 +296,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
+ Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
};
}
}
@@ -330,7 +330,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
+ Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
};
}
}
@@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).ToArray()
+ Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result.ToArray()
};
}
}
diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs
index e774c3077..2d7e909bf 100644
--- a/MediaBrowser.Api/Music/AlbumsService.cs
+++ b/MediaBrowser.Api/Music/AlbumsService.cs
@@ -8,6 +8,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
namespace MediaBrowser.Api.Music
{
@@ -49,18 +50,18 @@ namespace MediaBrowser.Api.Music
_dtoService = dtoService;
}
- public object Get(GetSimilarArtists request)
+ public async Task<object> Get(GetSimilarArtists request)
{
var dtoOptions = GetDtoOptions(request);
- var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
+ var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicArtist) },
- SimilarItemsHelper.GetSimiliarityScore);
+ SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -70,18 +71,18 @@ namespace MediaBrowser.Api.Music
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetSimilarAlbums request)
+ public async Task<object> Get(GetSimilarAlbums request)
{
var dtoOptions = GetDtoOptions(request);
- var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
+ var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicAlbum) },
- GetAlbumSimilarityScore);
+ GetAlbumSimilarityScore).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index d2a4aa60c..19265408b 100644
--- a/MediaBrowser.Api/Music/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
namespace MediaBrowser.Api.Music
{
@@ -76,7 +77,7 @@ namespace MediaBrowser.Api.Music
_libraryManager = libraryManager;
}
- public object Get(GetInstantMixFromItem request)
+ public Task<object> Get(GetInstantMixFromItem request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -87,7 +88,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromArtistId request)
+ public Task<object> Get(GetInstantMixFromArtistId request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -98,7 +99,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromMusicGenreId request)
+ public Task<object> Get(GetInstantMixFromMusicGenreId request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -109,7 +110,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromSong request)
+ public Task<object> Get(GetInstantMixFromSong request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -120,7 +121,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromAlbum request)
+ public Task<object> Get(GetInstantMixFromAlbum request)
{
var album = _libraryManager.GetItemById(request.Id);
@@ -131,7 +132,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromPlaylist request)
+ public Task<object> Get(GetInstantMixFromPlaylist request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
@@ -142,7 +143,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromMusicGenre request)
+ public Task<object> Get(GetInstantMixFromMusicGenre request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -151,7 +152,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- public object Get(GetInstantMixFromArtist request)
+ public Task<object> Get(GetInstantMixFromArtist request)
{
var user = _userManager.GetUserById(request.UserId);
var artist = _libraryManager.GetArtist(request.Name);
@@ -161,7 +162,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request);
}
- private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
+ private async Task<object> GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
{
var list = items.ToList();
@@ -172,7 +173,7 @@ namespace MediaBrowser.Api.Music
var dtoOptions = GetDtoOptions(request);
- result.Items = _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ToArray();
+ result.Items = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ConfigureAwait(false)).ToArray();
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/PackageReviewService.cs b/MediaBrowser.Api/PackageReviewService.cs
index e70d6a713..0a5b9bef8 100644
--- a/MediaBrowser.Api/PackageReviewService.cs
+++ b/MediaBrowser.Api/PackageReviewService.cs
@@ -112,7 +112,7 @@ namespace MediaBrowser.Api
_appHost = appHost;
}
- public object Get(ReviewRequest request)
+ public async Task<object> Get(ReviewRequest request)
{
var parms = "?id=" + request.Id;
@@ -133,11 +133,13 @@ namespace MediaBrowser.Api
parms += "&title=true";
}
- var result = _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None).Result;
-
- var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
+ using (var result = await _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None)
+ .ConfigureAwait(false))
+ {
+ var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
- return ToOptimizedResult(reviews);
+ return ToOptimizedResult(reviews);
+ }
}
public void Post(CreateReviewRequest request)
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index c65511074..7913f547a 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -846,7 +846,7 @@ namespace MediaBrowser.Api.Playback
if (MediaEncoder.SupportsDecoder("h264_qsv"))
{
// Seeing stalls and failures with decoding. Not worth it compared to encoding.
- //return "-c:v h264_qsv ";
+ return "-c:v h264_qsv ";
}
break;
case "mpeg2video":
@@ -1207,7 +1207,7 @@ namespace MediaBrowser.Api.Playback
}
}
- private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream)
+ private int? GetVideoBitrateParamValue(VideoStreamRequest request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@@ -1232,6 +1232,18 @@ namespace MediaBrowser.Api.Playback
}
}
+ if (bitrate.HasValue)
+ {
+ var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
+ bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
+
+ // If a max bitrate was requested, don't let the scaled bitrate exceed it
+ if (request.VideoBitRate.HasValue)
+ {
+ bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ }
+ }
+
return bitrate;
}
@@ -1692,7 +1704,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
state.OutputVideoCodec = state.VideoRequest.VideoCodec;
- state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream);
+ state.OutputVideoBitrate = GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 49f50735f..3d8957086 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -63,9 +63,9 @@ namespace MediaBrowser.Api.Playback.Hls
/// <param name="request">The request.</param>
/// <param name="isLive">if set to <c>true</c> [is live].</param>
/// <returns>System.Object.</returns>
- protected object ProcessRequest(StreamRequest request, bool isLive)
+ protected async Task<object> ProcessRequest(StreamRequest request, bool isLive)
{
- return ProcessRequestAsync(request, isLive).Result;
+ return await ProcessRequestAsync(request, isLive).ConfigureAwait(false);
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index f857a43e4..780e20f87 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -475,7 +475,7 @@ namespace MediaBrowser.Api.Playback.Hls
ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
}
}
- });
+ }).Result;
}
private async Task<object> GetMasterPlaylistInternal(StreamRequest request, string method)
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index e9f33161e..27deaf25e 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -5,6 +5,7 @@ using ServiceStack;
using System;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -89,7 +90,7 @@ namespace MediaBrowser.Api.Playback.Hls
_config = config;
}
- public object Get(GetHlsPlaylistLegacy request)
+ public Task<object> Get(GetHlsPlaylistLegacy request)
{
var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
@@ -107,7 +108,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetHlsVideoSegmentLegacy request)
+ public Task<object> Get(GetHlsVideoSegmentLegacy request)
{
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file);
@@ -131,10 +132,10 @@ namespace MediaBrowser.Api.Playback.Hls
var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
file = Path.Combine(_appPaths.TranscodingTempPath, file);
- return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite);
+ return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite).Result;
}
- private object GetFileResult(string path, string playlistPath)
+ private Task<object> GetFileResult(string path, string playlistPath)
{
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 032a0719c..e828a53c9 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using System.Collections.Generic;
+using System.Threading.Tasks;
using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
@@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetAudioStream request)
+ public Task<object> Get(GetAudioStream request)
{
return ProcessRequest(request, false);
}
@@ -50,7 +51,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Head(GetAudioStream request)
+ public Task<object> Head(GetAudioStream request)
{
return ProcessRequest(request, true);
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 3211f9e39..868d8d488 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -113,11 +113,11 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <param name="request">The request.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>Task.</returns>
- protected object ProcessRequest(StreamRequest request, bool isHeadRequest)
+ protected async Task<object> ProcessRequest(StreamRequest request, bool isHeadRequest)
{
var cancellationTokenSource = new CancellationTokenSource();
- var state = GetState(request, cancellationTokenSource.Token).Result;
+ var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false);
var responseHeaders = new Dictionary<string, string>();
@@ -128,7 +128,8 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state)
{
- return GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).Result;
+ return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource)
+ .ConfigureAwait(false);
}
}
@@ -138,7 +139,7 @@ namespace MediaBrowser.Api.Playback.Progressive
}
var outputPath = state.OutputFilePath;
- var outputPathExists = FileSystem.FileExists(outputPath);
+ var outputPathExists = FileSystem.FileExists(outputPath);
var isTranscodeCached = outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive);
@@ -151,13 +152,13 @@ namespace MediaBrowser.Api.Playback.Progressive
using (state)
{
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
ResponseHeaders = responseHeaders,
ContentType = contentType,
IsHeadRequest = isHeadRequest,
Path = state.MediaPath
- });
+ }).ConfigureAwait(false);
}
}
@@ -168,13 +169,13 @@ namespace MediaBrowser.Api.Playback.Progressive
try
{
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
ResponseHeaders = responseHeaders,
ContentType = contentType,
IsHeadRequest = isHeadRequest,
Path = outputPath
- });
+ }).ConfigureAwait(false);
}
finally
{
@@ -185,7 +186,8 @@ namespace MediaBrowser.Api.Playback.Progressive
// Need to start ffmpeg
try
{
- return GetStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).Result;
+ return await GetStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource)
+ .ConfigureAwait(false);
}
catch
{
@@ -229,7 +231,7 @@ namespace MediaBrowser.Api.Playback.Progressive
if (trySupportSeek)
{
- foreach (var name in new[] {"Content-Range", "Accept-Ranges"})
+ foreach (var name in new[] { "Content-Range", "Accept-Ranges" })
{
var val = response.Headers[name];
if (!string.IsNullOrWhiteSpace(val))
@@ -242,12 +244,12 @@ namespace MediaBrowser.Api.Playback.Progressive
{
responseHeaders["Accept-Ranges"] = "none";
}
-
+
if (response.ContentLength.HasValue)
{
responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
}
-
+
if (isHeadRequest)
{
using (response)
@@ -324,7 +326,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
TranscodingJob job;
- if (!FileSystem.FileExists(outputPath))
+ if (!FileSystem.FileExists(outputPath))
{
job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index be3995aeb..3fd67c51e 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.Serialization;
using ServiceStack;
using System;
using System.IO;
+using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Model.Dlna;
@@ -76,7 +77,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetVideoStream request)
+ public Task<object> Get(GetVideoStream request)
{
return ProcessRequest(request, false);
}
@@ -86,7 +87,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Head(GetVideoStream request)
+ public Task<object> Head(GetVideoStream request)
{
return ProcessRequest(request, true);
}
diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs
index 3dafd0eeb..604227a15 100644
--- a/MediaBrowser.Api/PlaylistService.cs
+++ b/MediaBrowser.Api/PlaylistService.cs
@@ -157,7 +157,7 @@ namespace MediaBrowser.Api
Task.WaitAll(task);
}
- public object Get(GetPlaylistItems request)
+ public async Task<object> Get(GetPlaylistItems request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -178,7 +178,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
- var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user)
+ var dtos = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user).ConfigureAwait(false))
.ToArray();
var index = 0;
diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs
index 537ffc913..c98a91a55 100644
--- a/MediaBrowser.Api/SimilarItemsHelper.cs
+++ b/MediaBrowser.Api/SimilarItemsHelper.cs
@@ -9,6 +9,8 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
{
@@ -54,7 +56,7 @@ namespace MediaBrowser.Api
/// </summary>
public static class SimilarItemsHelper
{
- internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
+ internal static async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
@@ -80,14 +82,14 @@ namespace MediaBrowser.Api
returnItems = returnItems.Take(request.Limit.Value);
}
- var result = new ItemsResult
+ var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false);
+
+ return new QueryResult<BaseItemDto>
{
- Items = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
+ Items = dtos.ToArray(),
TotalRecordCount = items.Count
};
-
- return result;
}
/// <summary>
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index dbb6478a1..f993bc4b1 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -11,6 +11,7 @@ using ServiceStack;
using System;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Api
{
@@ -52,14 +53,16 @@ namespace MediaBrowser.Api
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
private readonly ILiveTvManager _liveTvManager;
+ private readonly IMediaEncoder _mediaEncoder;
- public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager)
+ public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager, IMediaEncoder mediaEncoder)
{
_config = config;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
_liveTvManager = liveTvManager;
+ _mediaEncoder = mediaEncoder;
}
public void Post(ReportStartupWizardComplete request)
@@ -69,13 +72,14 @@ namespace MediaBrowser.Api
_config.SaveConfiguration();
}
- public object Get(GetStartupInfo request)
+ public async Task<object> Get(GetStartupInfo request)
{
- var info = _appHost.GetSystemInfo();
+ var info = await _appHost.GetSystemInfo().ConfigureAwait(false);
return new StartupInfo
{
- SupportsRunningAsService = info.SupportsRunningAsService
+ SupportsRunningAsService = info.SupportsRunningAsService,
+ HasMediaEncoder = !string.IsNullOrWhiteSpace(_mediaEncoder.EncoderPath)
};
}
@@ -114,7 +118,7 @@ namespace MediaBrowser.Api
config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true;
config.EnableFolderView = true;
- config.SchemaVersion = 89;
+ config.SchemaVersion = 96;
}
public void Post(UpdateStartupConfiguration request)
@@ -231,6 +235,7 @@ namespace MediaBrowser.Api
public class StartupInfo
{
public bool SupportsRunningAsService { get; set; }
+ public bool HasMediaEncoder { get; set; }
}
public class StartupUser
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 160fda065..fe13e8b21 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -210,7 +210,7 @@ namespace MediaBrowser.Api.Subtitles
var subtitleStream = mediaSource.MediaStreams
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index);
- return ToStaticFileResult(subtitleStream.Path);
+ return await ResultFactory.GetStaticFileResult(Request, subtitleStream.Path).ConfigureAwait(false);
}
using (var stream = await GetSubtitles(request).ConfigureAwait(false))
@@ -229,9 +229,9 @@ namespace MediaBrowser.Api.Subtitles
}
}
- private Task<Stream> GetSubtitles(GetSubtitle request)
+ private Task<Stream> GetSubtitles(GetSubtitle request)
{
- return _subtitleEncoder.GetSubtitles(request.Id,
+ return _subtitleEncoder.GetSubtitles(request.Id,
request.MediaSourceId,
request.Index,
request.Format,
@@ -264,9 +264,9 @@ namespace MediaBrowser.Api.Subtitles
return ToOptimizedResult(result);
}
- public object Get(GetRemoteSubtitles request)
+ public async Task<object> Get(GetRemoteSubtitles request)
{
- var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result;
+ var result = await _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).ConfigureAwait(false);
return ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format));
}
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index 593c3a108..a15ce216f 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -227,7 +227,7 @@ namespace MediaBrowser.Api.Sync
Task.WaitAll(task);
}
- public object Get(GetSyncJobItemFile request)
+ public async Task<object> Get(GetSyncJobItemFile request)
{
var jobItem = _syncManager.GetJobItem(request.Id);
@@ -241,10 +241,9 @@ namespace MediaBrowser.Api.Sync
throw new ArgumentException("The job item is not yet ready for transfer.");
}
- var task = _syncManager.ReportSyncJobItemTransferBeginning(request.Id);
- Task.WaitAll(task);
+ await _syncManager.ReportSyncJobItemTransferBeginning(request.Id).ConfigureAwait(false);
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
Path = jobItem.OutputPath,
OnError = () =>
@@ -252,10 +251,11 @@ namespace MediaBrowser.Api.Sync
var failedTask = _syncManager.ReportSyncJobItemTransferFailed(request.Id);
Task.WaitAll(failedTask);
}
- });
+
+ }).ConfigureAwait(false);
}
- public object Get(GetSyncDialogOptions request)
+ public async Task<object> Get(GetSyncDialogOptions request)
{
var result = new SyncDialogOptions();
@@ -298,8 +298,7 @@ namespace MediaBrowser.Api.Sync
.Select(_libraryManager.GetItemById)
.Where(i => i != null);
- var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser)
- .ToList();
+ var dtos = (await _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser).ConfigureAwait(false));
result.Options = SyncHelper.GetSyncOptions(dtos);
}
@@ -343,7 +342,7 @@ namespace MediaBrowser.Api.Sync
Task.WaitAll(task);
}
- public object Get(GetSyncJobItemAdditionalFile request)
+ public Task<object> Get(GetSyncJobItemAdditionalFile request)
{
var jobItem = _syncManager.GetJobItem(request.Id);
@@ -359,7 +358,7 @@ namespace MediaBrowser.Api.Sync
throw new ArgumentException("Sync job additional file not found.");
}
- return ToStaticFileResult(file.Path);
+ return ResultFactory.GetStaticFileResult(Request, file.Path);
}
public void Post(EnableSyncJobItem request)
diff --git a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
index 9ab7770ed..a53bfac27 100644
--- a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs
@@ -43,7 +43,7 @@ namespace MediaBrowser.Api.System
/// <returns>Task{SystemInfo}.</returns>
protected override Task<SystemInfo> GetDataToSend(WebSocketListenerState state)
{
- return Task.FromResult(_appHost.GetSystemInfo());
+ return _appHost.GetSystemInfo();
}
}
}
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index b4b41c844..c2318dccb 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Api.System
/// Class GetSystemInfo
/// </summary>
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
- [Authenticated(EscapeParentalControl = true)]
+ [Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)]
public class GetSystemInfo : IReturn<SystemInfo>
{
@@ -120,7 +120,7 @@ namespace MediaBrowser.Api.System
try
{
- files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
+ files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.Where(i => string.Equals(i.Extension, ".txt", StringComparison.OrdinalIgnoreCase))
.ToList();
}
@@ -144,9 +144,9 @@ namespace MediaBrowser.Api.System
return ToOptimizedResult(result);
}
- public object Get(GetLogFile request)
+ public Task<object> Get(GetLogFile request)
{
- var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
+ var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite);
@@ -157,16 +157,16 @@ namespace MediaBrowser.Api.System
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetSystemInfo request)
+ public async Task<object> Get(GetSystemInfo request)
{
- var result = _appHost.GetSystemInfo();
+ var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
return ToOptimizedResult(result);
}
- public object Get(GetPublicSystemInfo request)
+ public async Task<object> Get(GetPublicSystemInfo request)
{
- var result = _appHost.GetSystemInfo();
+ var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
var publicInfo = new PublicSystemInfo
{
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index 5ccfede1e..1c301f62e 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -12,6 +12,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api
@@ -272,14 +273,14 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetSimilarShows request)
+ public async Task<object> Get(GetSimilarShows request)
{
- var result = GetSimilarItemsResult(request);
+ var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(result);
}
- private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -302,7 +303,7 @@ namespace MediaBrowser.Api
var result = new QueryResult<BaseItemDto>
{
- Items = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ToArray(),
+ Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
TotalRecordCount = itemsResult.Count
};
@@ -310,7 +311,7 @@ namespace MediaBrowser.Api
return result;
}
- public object Get(GetUpcomingEpisodes request)
+ public async Task<object> Get(GetUpcomingEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -331,7 +332,7 @@ namespace MediaBrowser.Api
var options = GetDtoOptions(request);
- var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user).ToArray();
+ var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray();
var result = new ItemsResult
{
@@ -347,7 +348,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetNextUpEpisodes request)
+ public async Task<object> Get(GetNextUpEpisodes request)
{
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
{
@@ -362,7 +363,7 @@ namespace MediaBrowser.Api
var options = GetDtoOptions(request);
- var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user).ToArray();
+ var returnItems = (await _dtoService.GetBaseItemDtos(result.Items, options, user).ConfigureAwait(false)).ToArray();
return ToOptimizedSerializedResultUsingCache(new ItemsResult
{
@@ -395,7 +396,7 @@ namespace MediaBrowser.Api
return items;
}
- public object Get(GetSeasons request)
+ public async Task<object> Get(GetSeasons request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -426,7 +427,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
- var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user)
+ var returnItems = (await _dtoService.GetBaseItemDtos(seasons, dtoOptions, user).ConfigureAwait(false))
.ToArray();
return new ItemsResult
@@ -453,7 +454,7 @@ namespace MediaBrowser.Api
return items;
}
- public object Get(GetEpisodes request)
+ public async Task<object> Get(GetEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -535,7 +536,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(request);
- var dtos = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user)
+ var dtos = (await _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ConfigureAwait(false))
.ToArray();
return new ItemsResult
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index cde5eade5..df73ef720 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Dto;
+using System;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -8,6 +9,8 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@@ -100,7 +103,12 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetArtists request)
{
- var result = GetResult(request);
+ if (string.IsNullOrWhiteSpace(request.IncludeItemTypes))
+ {
+ //request.IncludeItemTypes = "Audio,MusicVideo";
+ }
+
+ var result = GetResultSlim(request);
return ToOptimizedResult(result);
}
@@ -112,11 +120,26 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetAlbumArtists request)
{
- var result = GetResult(request);
+ if (string.IsNullOrWhiteSpace(request.IncludeItemTypes))
+ {
+ //request.IncludeItemTypes = "Audio,MusicVideo";
+ }
+
+ var result = GetResultSlim(request);
return ToOptimizedResult(result);
}
+ protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
+ {
+ if (request is GetAlbumArtists)
+ {
+ return LibraryManager.GetAlbumArtists(query);
+ }
+
+ return LibraryManager.GetArtists(query);
+ }
+
/// <summary>
/// Gets all items.
/// </summary>
@@ -125,16 +148,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
- if (request is GetAlbumArtists)
- {
- return LibraryManager.GetAlbumArtists(items
- .Where(i => !i.IsFolder)
- .OfType<IHasAlbumArtist>());
- }
-
- return LibraryManager.GetArtists(items
- .Where(i => !i.IsFolder)
- .OfType<IHasArtist>());
+ throw new NotImplementedException();
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 18dec3253..9465d1fdc 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -8,6 +8,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Api.UserLibrary
{
@@ -83,6 +84,137 @@ namespace MediaBrowser.Api.UserLibrary
return null;
}
+ protected ItemsResult GetResultSlim(GetItemsByName request)
+ {
+ var dtoOptions = GetDtoOptions(request);
+
+ User user = null;
+ BaseItem parentItem;
+
+ if (!string.IsNullOrWhiteSpace(request.UserId))
+ {
+ user = UserManager.GetUserById(request.UserId);
+ parentItem = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : LibraryManager.GetItemById(request.ParentId);
+ }
+ else
+ {
+ parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
+ }
+
+ var excludeItemTypes = request.GetExcludeItemTypes();
+ var includeItemTypes = request.GetIncludeItemTypes();
+ var mediaTypes = request.GetMediaTypes();
+
+ var query = new InternalItemsQuery(user)
+ {
+ ExcludeItemTypes = excludeItemTypes,
+ IncludeItemTypes = includeItemTypes,
+ MediaTypes = mediaTypes,
+ StartIndex = request.StartIndex,
+ Limit = request.Limit,
+ IsFavorite = request.IsFavorite,
+ NameLessThan = request.NameLessThan,
+ NameStartsWith = request.NameStartsWith,
+ NameStartsWithOrGreater = request.NameStartsWithOrGreater,
+ AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater,
+ Tags = request.GetTags(),
+ OfficialRatings = request.GetOfficialRatings(),
+ Genres = request.GetGenres(),
+ GenreIds = request.GetGenreIds(),
+ Studios = request.GetStudios(),
+ StudioIds = request.GetStudioIds(),
+ Person = request.Person,
+ PersonIds = request.GetPersonIds(),
+ PersonTypes = request.GetPersonTypes(),
+ Years = request.GetYears(),
+ MinCommunityRating = request.MinCommunityRating
+ };
+
+ if (!string.IsNullOrWhiteSpace(request.ParentId))
+ {
+ if (parentItem is Folder)
+ {
+ query.AncestorIds = new[] { request.ParentId };
+ }
+ else
+ {
+ query.ItemIds = new[] { request.ParentId };
+ }
+ }
+
+ foreach (var filter in request.GetFilters())
+ {
+ switch (filter)
+ {
+ case ItemFilter.Dislikes:
+ query.IsLiked = false;
+ break;
+ case ItemFilter.IsFavorite:
+ query.IsFavorite = true;
+ break;
+ case ItemFilter.IsFavoriteOrLikes:
+ query.IsFavoriteOrLiked = true;
+ break;
+ case ItemFilter.IsFolder:
+ query.IsFolder = true;
+ break;
+ case ItemFilter.IsNotFolder:
+ query.IsFolder = false;
+ break;
+ case ItemFilter.IsPlayed:
+ query.IsPlayed = true;
+ break;
+ case ItemFilter.IsRecentlyAdded:
+ break;
+ case ItemFilter.IsResumable:
+ query.IsResumable = true;
+ break;
+ case ItemFilter.IsUnplayed:
+ query.IsPlayed = false;
+ break;
+ case ItemFilter.Likes:
+ query.IsLiked = true;
+ break;
+ }
+ }
+
+ var result = GetItems(request, query);
+
+ var dtos = result.Items.Select(i =>
+ {
+ var dto = DtoService.GetItemByNameDto(i.Item1, dtoOptions, null, user);
+
+ if (!string.IsNullOrWhiteSpace(request.IncludeItemTypes))
+ {
+ SetItemCounts(dto, i.Item2);
+ }
+ return dto;
+ });
+
+ return new ItemsResult
+ {
+ Items = dtos.ToArray(),
+ TotalRecordCount = result.TotalRecordCount
+ };
+ }
+
+ protected virtual QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
+ {
+ return new QueryResult<Tuple<BaseItem, ItemCounts>>();
+ }
+
+ private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
+ {
+ dto.ChildCount = counts.ItemCount;
+ dto.SeriesCount = counts.SeriesCount;
+ dto.EpisodeCount = counts.EpisodeCount;
+ dto.MovieCount = counts.MovieCount;
+ dto.TrailerCount = counts.TrailerCount;
+ dto.AlbumCount = counts.AlbumCount;
+ dto.SongCount = counts.SongCount;
+ dto.GameCount = counts.GameCount;
+ }
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -374,7 +506,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="includeItemTypes">The include item types.</param>
/// <param name="mediaTypes">The media types.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- protected bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
+ private bool FilterItem(GetItemsByName request, BaseItem f, string[] excludeItemTypes, string[] includeItemTypes, string[] mediaTypes)
{
// Exclude item types
if (excludeItemTypes.Length > 0)
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index 58237f80f..ebc9a970d 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -9,6 +9,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@@ -87,11 +88,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetGameGenres request)
{
- var result = GetResult(request);
+ var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
+ protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
+ {
+ return LibraryManager.GetGameGenres(query);
+ }
+
/// <summary>
/// Gets all items.
/// </summary>
@@ -100,22 +106,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .Select(name =>
- {
- try
- {
- return LibraryManager.GetGameGenre(name);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting genre {0}", ex, name);
- return null;
- }
- })
- .Where(i => i != null);
+ throw new NotImplementedException();
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index d383bd0ad..57c11a1fa 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -9,6 +9,7 @@ using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@@ -92,65 +93,37 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetGenres request)
{
- var result = GetResult(request);
+ var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
- /// <summary>
- /// Gets all items.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="items">The items.</param>
- /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
{
var viewType = GetParentItemViewType(request);
if (string.Equals(viewType, CollectionType.Music) || string.Equals(viewType, CollectionType.MusicVideos))
{
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .Select(name => LibraryManager.GetMusicGenre(name));
+ return LibraryManager.GetMusicGenres(query);
}
if (string.Equals(viewType, CollectionType.Games))
{
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .Select(name =>
- {
- try
- {
- return LibraryManager.GetGameGenre(name);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting genre {0}", ex, name);
- return null;
- }
- })
- .Where(i => i != null);
+ return LibraryManager.GetGameGenres(query);
}
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .Select(name =>
- {
- try
- {
- return LibraryManager.GetGenre(name);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting genre {0}", ex, name);
- return null;
- }
- })
- .Where(i => i != null);
+ return LibraryManager.GetGenres(query);
+ }
+
+ /// <summary>
+ /// Gets all items.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="items">The items.</param>
+ /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ {
+ throw new NotImplementedException();
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 644b28437..51ca2d5ca 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -92,7 +92,7 @@ namespace MediaBrowser.Api.UserLibrary
return new ItemsResult
{
TotalRecordCount = result.TotalRecordCount,
- Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray()
+ Items = (await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false)).ToArray()
};
}
@@ -119,11 +119,17 @@ namespace MediaBrowser.Api.UserLibrary
// Default list type = children
+ var folder = item as Folder;
+ if (folder == null)
+ {
+ folder = user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder();
+ }
+
if (!string.IsNullOrEmpty(request.Ids))
{
request.Recursive = true;
var query = GetItemsQuery(request, user);
- var result = await ((Folder)item).GetItems(query).ConfigureAwait(false);
+ var result = await folder.GetItems(query).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(request.SortBy))
{
@@ -138,22 +144,22 @@ namespace MediaBrowser.Api.UserLibrary
if (request.Recursive)
{
- return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
+ return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
if (user == null)
{
- return await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
+ return await folder.GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
}
var userRoot = item as UserRootFolder;
if (userRoot == null)
{
- return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
+ return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
}
- IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
+ IEnumerable<BaseItem> items = folder.GetChildren(user, true);
var itemsArray = items.ToArray();
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 12cb62fac..f02136e05 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Dto;
+using System;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -8,6 +9,8 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@@ -86,11 +89,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetMusicGenres request)
{
- var result = GetResult(request);
+ var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
+ protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
+ {
+ return LibraryManager.GetMusicGenres(query);
+ }
+
/// <summary>
/// Gets all items.
/// </summary>
@@ -99,10 +107,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .Select(name => LibraryManager.GetMusicGenre(name));
+ throw new NotImplementedException();
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index 94c391cb5..710d337ec 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -247,9 +247,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public object Post(MarkPlayedItem request)
+ public async Task<object> Post(MarkPlayedItem request)
{
- var result = MarkPlayed(request).Result;
+ var result = await MarkPlayed(request).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@@ -429,7 +429,7 @@ namespace MediaBrowser.Api.UserLibrary
await item.MarkUnplayed(user).ConfigureAwait(false);
}
- return _userDataRepository.GetUserDataDto(item, user);
+ return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index 2cdabf721..9e9c25d78 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Dto;
+using System;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
@@ -7,6 +8,7 @@ using MediaBrowser.Model.Dto;
using ServiceStack;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Api.UserLibrary
{
@@ -90,11 +92,16 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
public object Get(GetStudios request)
{
- var result = GetResult(request);
+ var result = GetResultSlim(request);
return ToOptimizedSerializedResultUsingCache(result);
}
+ protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
+ {
+ return LibraryManager.GetStudios(query);
+ }
+
/// <summary>
/// Gets all items.
/// </summary>
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 8cc5cab35..3be11bdc5 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -488,9 +488,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public object Post(MarkFavoriteItem request)
+ public async Task<object> Post(MarkFavoriteItem request)
{
- var dto = MarkFavorite(request.UserId, request.Id, true).Result;
+ var dto = await MarkFavorite(request.UserId, request.Id, true).ConfigureAwait(false);
return ToOptimizedResult(dto);
}
@@ -527,7 +527,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
- return _userDataRepository.GetUserDataDto(item, user);
+ return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
/// <summary>
@@ -545,9 +545,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public object Post(UpdateUserItemRating request)
+ public async Task<object> Post(UpdateUserItemRating request)
{
- var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes).Result;
+ var dto = await UpdateUserItemRating(request.UserId, request.Id, request.Likes).ConfigureAwait(false);
return ToOptimizedResult(dto);
}
@@ -572,7 +572,7 @@ namespace MediaBrowser.Api.UserLibrary
await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
- return _userDataRepository.GetUserDataDto(item, user);
+ return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
}
}
}
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 9b611c397..07ff36c41 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -385,7 +385,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false);
await _userManager.DeleteUser(user).ConfigureAwait(false);
}
@@ -465,6 +465,10 @@ namespace MediaBrowser.Api
}
await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
+
+ var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
+
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
}
@@ -602,7 +606,8 @@ namespace MediaBrowser.Api
throw new ArgumentException("There must be at least one enabled user in the system.");
}
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false);
+ var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token;
+ await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
}
await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index f9dbd766f..ce1e9fd7f 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -143,7 +143,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
- private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
+ private WebRequest GetRequest(HttpRequestOptions options, string method)
{
var request = CreateWebRequest(options.Url);
var httpWebRequest = request as HttpWebRequest;
@@ -154,7 +154,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
AddRequestHeaders(httpWebRequest, options);
- httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
+ httpWebRequest.AutomaticDecompression = options.EnableHttpCompression ?
+ (options.DecompressionMethod ?? DecompressionMethods.Deflate) :
+ DecompressionMethods.None;
}
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
@@ -366,7 +368,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
};
}
- var httpWebRequest = GetRequest(options, httpMethod, options.EnableHttpCompression);
+ var httpWebRequest = GetRequest(options, httpMethod);
if (options.RequestContentBytes != null ||
!string.IsNullOrEmpty(options.RequestContent) ||
@@ -556,7 +558,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested();
- var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression);
+ var httpWebRequest = GetRequest(options, "GET");
if (options.ResourcePool != null)
{
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index 75368a5fc..1a7f414a7 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Threading;
namespace MediaBrowser.Common.Net
@@ -16,6 +17,8 @@ namespace MediaBrowser.Common.Net
/// <value>The URL.</value>
public string Url { get; set; }
+ public DecompressionMethods? DecompressionMethod { get; set; }
+
/// <summary>
/// Gets or sets the accept header.
/// </summary>
diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
index 587023ab4..57c2f1f7f 100644
--- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
+++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs
@@ -53,6 +53,12 @@ namespace MediaBrowser.Controller.Channels
public bool IsInfiniteStream { get; set; }
+ public string HomePageUrl { get; set; }
+
+ public List<string> Artists { get; set; }
+
+ public List<string> AlbumArtists { get; set; }
+
public ChannelItemInfo()
{
MediaSources = new List<ChannelMediaInfo>();
@@ -62,6 +68,8 @@ namespace MediaBrowser.Controller.Channels
People = new List<PersonInfo>();
Tags = new List<string>();
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ Artists = new List<string>();
+ AlbumArtists = new List<string>();
}
}
}
diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs
index 676ef9c56..27e06fb8d 100644
--- a/MediaBrowser.Controller/Chapters/IChapterManager.cs
+++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs
@@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Chapters
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveChapters(string itemId, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
+ Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Searches the specified video.
diff --git a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
index edc4f8558..92a7f5ac9 100644
--- a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs
@@ -23,10 +23,5 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <value>The height.</value>
public int Height { get; set; }
- /// <summary>
- /// Gets or sets the text.
- /// </summary>
- /// <value>The text.</value>
- public string Text { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index 5f0442f93..e4aa466df 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using System.Collections.Generic;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Dto
{
@@ -68,7 +69,7 @@ namespace MediaBrowser.Controller.Dto
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
/// <returns>IEnumerable&lt;BaseItemDto&gt;.</returns>
- IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
+ Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
BaseItem owner = null);
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 06710b030..b3df34c4d 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -26,8 +26,6 @@ namespace MediaBrowser.Controller.Entities.Audio
{
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
- public long? Size { get; set; }
- public string Container { get; set; }
public int? TotalBitrate { get; set; }
public ExtraType? ExtraType { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index c1743c749..6790a1bcf 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -79,6 +80,15 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
+ public override int GetChildCount(User user)
+ {
+ if (IsAccessedByName)
+ {
+ return 0;
+ }
+ return base.GetChildCount(user);
+ }
+
public override bool IsSaveLocalMetadataEnabled()
{
if (IsAccessedByName)
@@ -156,10 +166,17 @@ namespace MediaBrowser.Controller.Entities.Audio
list.Add("Artist-Musicbrainz-" + id);
}
- list.Add("Artist-" + item.Name);
+ list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return "Artist-" + (Name ?? string.Empty).RemoveDiacritics();
+ }
+ }
protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Music);
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index 77cf0cc49..798bc79fb 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -14,10 +15,18 @@ namespace MediaBrowser.Controller.Entities.Audio
{
var list = base.GetUserDataKeys();
- list.Insert(0, "MusicGenre-" + Name);
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return GetUserDataKeys()[0];
+ }
+ }
+
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index a45a462df..707ab0c24 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -69,8 +69,15 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string PreferredMetadataLanguage { get; set; }
+ public long? Size { get; set; }
+ public string Container { get; set; }
+ public string ShortOverview { get; set; }
+
public List<ItemImageInfo> ImageInfos { get; set; }
+ [IgnoreDataMember]
+ public bool IsVirtualItem { get; set; }
+
/// <summary>
/// Gets or sets the album.
/// </summary>
@@ -2086,7 +2093,7 @@ namespace MediaBrowser.Controller.Entities
return path;
}
- public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
+ public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
{
if (RunTimeTicks.HasValue)
{
@@ -2102,6 +2109,8 @@ namespace MediaBrowser.Controller.Entities
}
}
}
+
+ return Task.FromResult(true);
}
protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, string path, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 2e4cf3745..f12c51ff3 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -13,6 +13,7 @@ using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Controller.Channels;
using MediaBrowser.Model.Channels;
namespace MediaBrowser.Controller.Entities
@@ -216,7 +217,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- return LoadChildren().Select(LibraryManager.GetItemById).Where(i => i != null);
+ return LoadChildren();
}
}
@@ -270,7 +271,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads our children. Validation will occur externally.
/// We want this sychronous.
/// </summary>
- protected virtual IEnumerable<Guid> LoadChildren()
+ protected virtual IEnumerable<BaseItem> LoadChildren()
{
//just load our children from the repo - the library will be validated and maintained in other processes
return GetCachedChildren();
@@ -657,15 +658,36 @@ namespace MediaBrowser.Controller.Entities
/// Get our children from the repo - stubbed for now
/// </summary>
/// <returns>IEnumerable{BaseItem}.</returns>
- protected IEnumerable<Guid> GetCachedChildren()
+ protected IEnumerable<BaseItem> GetCachedChildren()
{
- return ItemRepository.GetItemIdsList(new InternalItemsQuery
+ return ItemRepository.GetItemList(new InternalItemsQuery
{
ParentId = Id,
GroupByPresentationUniqueKey = false
});
}
+ public virtual int GetChildCount(User user)
+ {
+ if (LinkedChildren.Count > 0)
+ {
+ if (!(this is ICollectionFolder))
+ {
+ return GetChildren(user, true).Count();
+ }
+ }
+
+ var result = GetItems(new InternalItemsQuery(user)
+ {
+ Recursive = false,
+ Limit = 0,
+ ParentId = Id
+
+ }).Result;
+
+ return result.TotalRecordCount;
+ }
+
public QueryResult<BaseItem> QueryRecursive(InternalItemsQuery query)
{
var user = query.User;
@@ -875,7 +897,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
+ if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User, ConfigurationManager))
{
Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
return true;
@@ -983,7 +1005,7 @@ namespace MediaBrowser.Controller.Entities
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query)
{
- return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager);
+ return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager);
}
public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
@@ -1401,72 +1423,61 @@ namespace MediaBrowser.Controller.Entities
{
return false;
}
+ if (this is Channel)
+ {
+ return false;
+ }
+ if (SourceType != SourceType.Library)
+ {
+ return false;
+ }
return true;
}
}
- public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
+ public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
{
if (!SupportsUserDataFromChildren)
{
return;
}
- var recursiveItemCount = 0;
- var unplayed = 0;
-
- double totalPercentPlayed = 0;
-
- var itemsResult = GetItems(new InternalItemsQuery(user)
+ var unplayedQueryResult = await GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
- ExcludeLocationTypes = new[] { LocationType.Virtual },
- EnableTotalRecordCount = false
+ IsVirtualItem = false,
+ EnableTotalRecordCount = true,
+ Limit = 0,
+ IsPlayed = false
- }).Result;
-
- var children = itemsResult.Items;
+ }).ConfigureAwait(false);
- // Loop through each recursive child
- foreach (var child in children)
+ var allItemsQueryResult = await GetItems(new InternalItemsQuery(user)
{
- recursiveItemCount++;
-
- var isUnplayed = true;
-
- var itemUserData = UserDataManager.GetUserData(user, child);
-
- // Incrememt totalPercentPlayed
- if (itemUserData != null)
- {
- if (itemUserData.Played)
- {
- totalPercentPlayed += 100;
+ Recursive = true,
+ IsFolder = false,
+ IsVirtualItem = false,
+ EnableTotalRecordCount = true,
+ Limit = 0
- isUnplayed = false;
- }
- else if (itemUserData.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
- {
- double itemPercent = itemUserData.PlaybackPositionTicks;
- itemPercent /= child.RunTimeTicks.Value;
- totalPercentPlayed += itemPercent;
- }
- }
+ }).ConfigureAwait(false);
- if (isUnplayed)
- {
- unplayed++;
- }
+ if (itemDto != null)
+ {
+ itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount;
}
- dto.UnplayedItemCount = unplayed;
+ double recursiveItemCount = allItemsQueryResult.TotalRecordCount;
+ double unplayedCount = unplayedQueryResult.TotalRecordCount;
if (recursiveItemCount > 0)
{
- dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
+ var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100;
+ dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
+ dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
index 7c1e88cb1..45e766c0f 100644
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ b/MediaBrowser.Controller/Entities/GameGenre.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -11,10 +12,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
- list.Insert(0, "GameGenre-" + Name);
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return GetUserDataKeys()[0];
+ }
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index c87d4daaf..cc5aebb2a 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Audio;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -15,10 +16,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
- list.Insert(0, "Genre-" + Name);
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return GetUserDataKeys()[0];
+ }
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index 244b319bd..2495b0ccd 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Entities
@@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="dto">The dto.</param>
/// <param name="userData">The user data.</param>
/// <param name="user">The user.</param>
- void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
+ Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
bool EnableRememberingTrackSelections { get; }
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 04dfc9491..e193a9dad 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -110,6 +110,7 @@ namespace MediaBrowser.Controller.Entities
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
public int? ParentIndexNumber { get; set; }
+ public int? ParentIndexNumberNotEquals { get; set; }
public int? IndexNumber { get; set; }
public int? MinParentalRating { get; set; }
public int? MaxParentalRating { get; set; }
@@ -117,6 +118,7 @@ namespace MediaBrowser.Controller.Entities
public bool? IsCurrentSchema { get; set; }
public bool? HasDeadParentId { get; set; }
public bool? IsOffline { get; set; }
+ public bool? IsVirtualItem { get; set; }
public Guid? ParentId { get; set; }
public string[] AncestorIds { get; set; }
@@ -140,7 +142,8 @@ namespace MediaBrowser.Controller.Entities
public bool GroupByPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
- public Dictionary<string,string> ExcludeProviderIds { get; set; }
+ public Dictionary<string, string> ExcludeProviderIds { get; set; }
+ public string GroupByAncestorOfType { get; set; }
public InternalItemsQuery()
{
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index 2b099e3d5..8ef0d70bf 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@@ -22,10 +23,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
- list.Insert(0, "Person-" + Name);
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return GetUserDataKeys()[0];
+ }
+ }
+
public PersonLookupInfo GetLookupInfo()
{
return GetItemLookupInfo<PersonLookupInfo>();
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index e46978af3..762798b55 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -14,10 +15,18 @@ namespace MediaBrowser.Controller.Entities
{
var list = base.GetUserDataKeys();
- list.Insert(0, "Studio-" + Name);
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
return list;
}
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ return GetUserDataKeys()[0];
+ }
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index f07d4be13..9a9014844 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -75,6 +75,11 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
/// <summary>
/// This Episode's Series Instance
/// </summary>
@@ -128,39 +133,16 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
- public override bool RequiresRefresh()
- {
- var result = base.RequiresRefresh();
-
- if (!result)
- {
- if (!IsVirtualItem.HasValue)
- {
- return true;
- }
- }
-
- return result;
- }
-
- [IgnoreDataMember]
- public bool? IsVirtualItem { get; set; }
-
[IgnoreDataMember]
public bool IsMissingSeason
{
- get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; }
+ get { return (IsVirtualItem) && !IsUnaired; }
}
[IgnoreDataMember]
public bool IsVirtualUnaired
{
- get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; }
- }
-
- private bool DetectIsVirtualItem()
- {
- return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual);
+ get { return (IsVirtualItem) && IsUnaired; }
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index a24148360..1cc496b35 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -31,7 +31,6 @@ namespace MediaBrowser.Controller.Entities.TV
RemoteTrailers = new List<MediaUrl>();
LocalTrailerIds = new List<Guid>();
RemoteTrailerIds = new List<Guid>();
- DisplaySpecialsWithSeasons = true;
}
[IgnoreDataMember]
@@ -58,8 +57,6 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- public bool DisplaySpecialsWithSeasons { get; set; }
-
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
@@ -95,10 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return GetRecursiveChildren(i => i is Episode)
- .Select(i => i.DateCreated)
- .OrderByDescending(i => i)
- .FirstOrDefault();
+ return DateLastMediaAdded ?? DateTime.MinValue;
}
}
@@ -117,6 +111,20 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
+ public override int GetChildCount(User user)
+ {
+ var result = LibraryManager.GetItemsResult(new InternalItemsQuery(user)
+ {
+ AncestorWithPresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Season).Name },
+ SortBy = new[] { ItemSortBy.SortName },
+ IsVirtualItem = false,
+ Limit = 0
+ });
+
+ return result.TotalRecordCount;
+ }
+
/// <summary>
/// Gets the user data key.
/// </summary>
@@ -192,16 +200,25 @@ namespace MediaBrowser.Controller.Entities.TV
var user = query.User;
- Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
-
- IEnumerable<BaseItem> items;
+ if (query.Recursive)
+ {
+ query.AncestorWithPresentationUniqueKey = PresentationUniqueKey;
+ if (query.SortBy.Length == 0)
+ {
+ query.SortBy = new[] { ItemSortBy.SortName };
+ }
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
+ }
+ query.IsVirtualItem = false;
+ return Task.FromResult(LibraryManager.GetItemsResult(query));
+ }
- items = query.Recursive
- ? GetSeasons(user).Cast<BaseItem>().Concat(GetEpisodes(user)).Where(filter)
- : GetSeasons(user).Where(filter);
+ Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
+ var items = GetSeasons(user).Where(filter);
var result = PostFilterAndSort(items, query);
-
return Task.FromResult(result);
}
@@ -243,6 +260,7 @@ namespace MediaBrowser.Controller.Entities.TV
AncestorWithPresentationUniqueKey = PresentationUniqueKey,
IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name },
SortBy = new[] { ItemSortBy.SortName }
+
}).ToList();
var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
@@ -357,7 +375,7 @@ namespace MediaBrowser.Controller.Entities.TV
return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes);
}
- var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, DisplaySpecialsWithSeasons);
+ var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons);
if (!includeMissingEpisodes)
{
@@ -405,47 +423,31 @@ namespace MediaBrowser.Controller.Entities.TV
public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
{
var seasonNumber = parentSeason.IndexNumber;
- if (!includeSpecials || (seasonNumber.HasValue && seasonNumber.Value == 0))
- {
- var seasonPresentationKey = parentSeason.PresentationUniqueKey;
+ var seasonPresentationKey = parentSeason.PresentationUniqueKey;
- return episodes.Where(i =>
- {
- if ((i.ParentIndexNumber ?? -1) == seasonNumber)
- {
- return true;
- }
- if (!i.ParentIndexNumber.HasValue)
- {
- var season = i.Season;
- return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
- }
-
- return false;
- });
- }
- else
- {
- var seasonPresentationKey = parentSeason.PresentationUniqueKey;
+ var supportSpecialsInSeason = includeSpecials && seasonNumber.HasValue && seasonNumber.Value != 0;
- return episodes.Where(episode =>
+ return episodes.Where(episode =>
+ {
+ var currentSeasonNumber = supportSpecialsInSeason ? episode.AiredSeasonNumber : episode.ParentIndexNumber;
+ if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
{
- var currentSeasonNumber = episode.AiredSeasonNumber;
+ return true;
+ }
- if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
- {
- return true;
- }
+ if (!currentSeasonNumber.HasValue && !seasonNumber.HasValue && parentSeason.LocationType == LocationType.Virtual)
+ {
+ return true;
+ }
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
- return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
- }
+ if (!episode.ParentIndexNumber.HasValue)
+ {
+ var season = episode.Season;
+ return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
+ }
- return false;
- });
- }
+ return false;
+ });
}
protected override bool GetBlockUnratedValue(UserPolicy config)
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 37c4c91b1..8e6f11c2c 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -38,6 +38,11 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(result.Where(filter), query);
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
[IgnoreDataMember]
protected override bool SupportsShortcutChildren
{
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index e40d9ca38..35375e7e6 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -45,6 +45,11 @@ namespace MediaBrowser.Controller.Entities
return list;
}
+ public override int GetChildCount(User user)
+ {
+ return GetChildren(user, true).Count();
+ }
+
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
var parent = this as Folder;
@@ -58,7 +63,7 @@ namespace MediaBrowser.Controller.Entities
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
- return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
+ return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager, PlaylistManager)
.GetUserItems(parent, this, ViewType, query);
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index a7b23112e..0cb806274 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -18,6 +18,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.Entities
{
@@ -30,10 +32,10 @@ namespace MediaBrowser.Controller.Entities
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITVSeriesManager _tvSeriesManager;
- private readonly ICollectionManager _collectionManager;
+ private readonly IServerConfigurationManager _config;
private readonly IPlaylistManager _playlistManager;
- public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
+ public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config, IPlaylistManager playlistManager)
{
_userViewManager = userViewManager;
_liveTvManager = liveTvManager;
@@ -42,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
_logger = logger;
_userDataManager = userDataManager;
_tvSeriesManager = tvSeriesManager;
- _collectionManager = collectionManager;
+ _config = config;
_playlistManager = playlistManager;
}
@@ -159,7 +161,7 @@ namespace MediaBrowser.Controller.Entities
return await GetTvGenres(queryParent, user, query).ConfigureAwait(false);
case SpecialFolder.TvGenre:
- return await GetTvGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false);
+ return GetTvGenreItems(queryParent, displayParent, user, query);
case SpecialFolder.TvResume:
return GetTvResume(queryParent, user, query);
@@ -663,6 +665,7 @@ namespace MediaBrowser.Controller.Entities
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
+ query.ExcludeLocationTypes = new[] { LocationType.Virtual };
return _libraryManager.GetItemsResult(query);
}
@@ -740,7 +743,7 @@ namespace MediaBrowser.Controller.Entities
return GetResult(genres, parent, query);
}
- private async Task<QueryResult<BaseItem>> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
+ private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
{
query.Recursive = true;
query.ParentId = queryParent.Id;
@@ -769,7 +772,7 @@ namespace MediaBrowser.Controller.Entities
{
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
- return PostFilterAndSort(items, queryParent, null, query, _libraryManager);
+ return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
}
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
@@ -782,14 +785,15 @@ namespace MediaBrowser.Controller.Entities
int? totalRecordLimit,
InternalItemsQuery query)
{
- return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager);
+ return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config);
}
public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
BaseItem queryParent,
int? totalRecordLimit,
InternalItemsQuery query,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ IServerConfigurationManager configurationManager)
{
var user = query.User;
@@ -798,7 +802,7 @@ namespace MediaBrowser.Controller.Entities
query.IsVirtualUnaired,
query.IsUnaired);
- items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user);
+ items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager);
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
@@ -812,14 +816,15 @@ namespace MediaBrowser.Controller.Entities
public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items,
InternalItemsQuery query,
BaseItem queryParent,
- User user)
+ User user,
+ IServerConfigurationManager configurationManager)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
- if (CollapseBoxSetItems(query, queryParent, user))
+ if (CollapseBoxSetItems(query, queryParent, user, configurationManager))
{
items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user);
}
@@ -852,7 +857,8 @@ namespace MediaBrowser.Controller.Entities
public static bool CollapseBoxSetItems(InternalItemsQuery query,
BaseItem queryParent,
- User user)
+ User user,
+ IServerConfigurationManager configurationManager)
{
// Could end up stuck in a loop like this
if (queryParent is BoxSet)
@@ -864,7 +870,7 @@ namespace MediaBrowser.Controller.Entities
if (!param.HasValue)
{
- if (user != null && !user.Configuration.GroupMoviesIntoBoxSets)
+ if (user != null && !configurationManager.Configuration.EnableGroupingIntoCollections)
{
return false;
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 2502033c8..73c893dd6 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -58,10 +58,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- public long? Size { get; set; }
- public string Container { get; set; }
public int? TotalBitrate { get; set; }
- public string ShortOverview { get; set; }
public ExtraType? ExtraType { get; set; }
/// <summary>
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 65eed1a23..f4c0e7658 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.System;
using System;
using System.Collections.Generic;
using System.Net;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller
{
@@ -17,7 +18,7 @@ namespace MediaBrowser.Controller
/// Gets the system info.
/// </summary>
/// <returns>SystemInfo.</returns>
- SystemInfo GetSystemInfo();
+ Task<SystemInfo> GetSystemInfo();
/// <summary>
/// Gets a value indicating whether [supports automatic run at startup].
@@ -65,13 +66,13 @@ namespace MediaBrowser.Controller
/// Gets the local ip address.
/// </summary>
/// <value>The local ip address.</value>
- List<IPAddress> LocalIpAddresses { get; }
+ Task<List<IPAddress>> GetLocalIpAddresses();
/// <summary>
/// Gets the local API URL.
/// </summary>
/// <value>The local API URL.</value>
- string LocalApiUrl { get; }
+ Task<string> GetLocalApiUrl();
/// <summary>
/// Gets the local API URL.
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 936b97c6e..4e641b005 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Library
{
@@ -151,13 +152,6 @@ namespace MediaBrowser.Controller.Library
BaseItem GetItemById(Guid id);
/// <summary>
- /// Gets the memory item by identifier.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>BaseItem.</returns>
- BaseItem GetMemoryItemById(Guid id);
-
- /// <summary>
/// Gets the intros.
/// </summary>
/// <param name="item">The item.</param>
@@ -574,5 +568,12 @@ namespace MediaBrowser.Controller.Library
void RemoveVirtualFolder(string name, bool refreshLibrary);
void AddMediaPath(string virtualFolderName, string path);
void RemoveMediaPath(string virtualFolderName, string path);
+
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index e2358650b..86c52c4c3 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -40,7 +40,9 @@ namespace MediaBrowser.Controller.Library
/// <param name="item">The item.</param>
/// <param name="user">The user.</param>
/// <returns>UserItemDataDto.</returns>
- UserItemDataDto GetUserDataDto(IHasUserData item, User user);
+ Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user);
+
+ Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user);
/// <summary>
/// Get all user data for the given user
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
index f5048bdda..5ecd70cc5 100644
--- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -15,5 +15,6 @@ namespace MediaBrowser.Controller.LiveTv
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
+ Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index a4bd32fff..ffba3097c 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.LiveTv
{
@@ -385,5 +386,15 @@ namespace MediaBrowser.Controller.LiveTv
List<NameValuePair> GetSatIniMappings();
Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
+
+ Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
+ Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
+
+ List<IListingsProvider> ListingProviders { get;}
+
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
index 4ef4847a3..d7d8336d0 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -226,4 +226,23 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns>
Task ResetTuner(string id, CancellationToken cancellationToken);
}
+
+ public interface ISupportsNewTimerIds
+ {
+ /// <summary>
+ /// Creates the timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the series timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken);
+ }
}
diff --git a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
new file mode 100644
index 000000000..0e1a05475
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class TimerEventInfo
+ {
+ public string Id { get; set; }
+ public string ProgramId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 4cfdc641c..9b4c35c41 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -218,6 +218,7 @@
<Compile Include="LiveTv\ProgramInfo.cs" />
<Compile Include="LiveTv\RecordingInfo.cs" />
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
+ <Compile Include="LiveTv\TimerEventInfo.cs" />
<Compile Include="LiveTv\TimerInfo.cs" />
<Compile Include="Localization\ILocalizationManager.cs" />
<Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 7c3959f6e..77ba1685f 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -20,12 +20,6 @@ namespace MediaBrowser.Controller.MediaEncoding
string EncoderPath { get; }
/// <summary>
- /// Gets the version.
- /// </summary>
- /// <value>The version.</value>
- string Version { get; }
-
- /// <summary>
/// Supportses the decoder.
/// </summary>
/// <param name="decoder">The decoder.</param>
@@ -134,5 +128,9 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="path">The path.</param>
/// <returns>System.String.</returns>
string EscapeSubtitleFilterPath(string path);
+
+ void Init();
+
+ Task UpdateEncoderPath(string path);
}
}
diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
index 526bf4be2..cd7ee603e 100644
--- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs
+++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
@@ -80,7 +80,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="responseHeaders">The response headers.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>System.Object.</returns>
- object GetStaticResult(IRequest requestContext,
+ Task<object> GetStaticResult(IRequest requestContext,
Guid cacheKey,
DateTime? lastDateModified,
TimeSpan? cacheDuration,
@@ -94,7 +94,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestContext">The request context.</param>
/// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
- object GetStaticResult(IRequest requestContext, StaticResultOptions options);
+ Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options);
/// <summary>
/// Gets the static file result.
@@ -103,7 +103,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="path">The path.</param>
/// <param name="fileShare">The file share.</param>
/// <returns>System.Object.</returns>
- object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
+ Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
/// <summary>
/// Gets the static file result.
@@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestContext">The request context.</param>
/// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
- object GetStaticFileResult(IRequest requestContext,
+ Task<object> GetStaticFileResult(IRequest requestContext,
StaticFileResultOptions options);
}
}
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 7bcc36958..78138999c 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Persistence
@@ -81,7 +82,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="chapters">The chapters.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken);
+ Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken);
/// <summary>
/// Gets the media streams.
@@ -97,7 +98,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="streams">The streams.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
+ Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the item ids.
@@ -153,7 +154,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="query">The query.</param>
/// <returns>List&lt;BaseItem&gt;.</returns>
- IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
+ List<BaseItem> GetItemList(InternalItemsQuery query);
/// <summary>
/// Updates the inherited values.
@@ -161,6 +162,13 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task UpdateInheritedValues(CancellationToken cancellationToken);
+
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
}
}
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index d16a73028..63cc48058 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -1,3 +1,4 @@
+using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
@@ -5,10 +6,6 @@ namespace MediaBrowser.Controller.Providers
{
public class ItemInfo
{
- public ItemInfo()
- {
- }
-
public ItemInfo(IHasMetadata item)
{
Path = item.Path;
@@ -21,8 +18,11 @@ namespace MediaBrowser.Controller.Providers
VideoType = video.VideoType;
IsPlaceHolder = video.IsPlaceHolder;
}
+
+ ItemType = item.GetType();
}
+ public Type ItemType { get; set; }
public string Path { get; set; }
public string ContainingFolderPath { get; set; }
public VideoType VideoType { get; set; }
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index fa74c5749..6659d1553 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -315,9 +315,8 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Revokes the user tokens.
/// </summary>
- /// <param name="userId">The user identifier.</param>
/// <returns>Task.</returns>
- Task RevokeUserTokens(string userId);
+ Task RevokeUserTokens(string userId, string currentAccessToken);
/// <summary>
/// Revokes the token.
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index af833a85c..b28cffd6d 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -846,7 +846,7 @@ namespace MediaBrowser.Dlna.Didl
if (item is Video)
{
- var userData = _userDataManager.GetUserDataDto(item, _user);
+ var userData = _userDataManager.GetUserDataDto(item, _user).Result;
playbackPercentage = Convert.ToInt32(userData.PlayedPercentage ?? 0);
if (playbackPercentage >= 100 || userData.Played)
@@ -856,7 +856,7 @@ namespace MediaBrowser.Dlna.Didl
}
else if (item is Series || item is Season || item is BoxSet)
{
- var userData = _userDataManager.GetUserDataDto(item, _user);
+ var userData = _userDataManager.GetUserDataDto(item, _user).Result;
if (userData.Played)
{
@@ -1015,17 +1015,17 @@ namespace MediaBrowser.Dlna.Didl
int? width = null;
int? height = null;
- //try
- //{
- // var size = _imageProcessor.GetImageSize(imageInfo);
+ try
+ {
+ var size = _imageProcessor.GetImageSize(imageInfo);
- // width = Convert.ToInt32(size.Width);
- // height = Convert.ToInt32(size.Height);
- //}
- //catch
- //{
+ width = Convert.ToInt32(size.Width);
+ height = Convert.ToInt32(size.Height);
+ }
+ catch
+ {
- //}
+ }
var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
.TrimStart('.')
diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
index 22f308979..b9d9944ec 100644
--- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
+++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Dlna.Channels;
@@ -105,7 +106,7 @@ namespace MediaBrowser.Dlna.Main
}
}
- private void ReloadComponents()
+ private async void ReloadComponents()
{
var options = _config.GetDlnaConfiguration();
@@ -130,7 +131,7 @@ namespace MediaBrowser.Dlna.Main
if (options.EnableServer && !isServerStarted)
{
- StartDlnaServer();
+ await StartDlnaServer().ConfigureAwait(false);
}
else if (!options.EnableServer && isServerStarted)
{
@@ -208,11 +209,11 @@ namespace MediaBrowser.Dlna.Main
}
}
- public void StartDlnaServer()
+ public async Task StartDlnaServer()
{
try
{
- RegisterServerEndpoints();
+ await RegisterServerEndpoints().ConfigureAwait(false);
_dlnaServerStarted = true;
}
@@ -222,9 +223,9 @@ namespace MediaBrowser.Dlna.Main
}
}
- private void RegisterServerEndpoints()
+ private async Task RegisterServerEndpoints()
{
- foreach (var address in _appHost.LocalIpAddresses)
+ foreach (var address in await _appHost.GetLocalIpAddresses().ConfigureAwait(false))
{
//if (IPAddress.IsLoopback(address))
//{
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index 80bb756ef..982742c06 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
return false;
}
-
+
return _device != null;
}
}
@@ -119,7 +119,7 @@ namespace MediaBrowser.Dlna.PlayTo
string nt;
if (!e.Headers.TryGetValue("NT", out nt)) nt = String.Empty;
- if ( usn.IndexOf(_device.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1 &&
+ if (usn.IndexOf(_device.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1 &&
!_disposed)
{
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) != -1 ||
@@ -141,7 +141,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
try
{
- var streamInfo = StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager, _mediaSourceManager);
+ var streamInfo = await StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (streamInfo.Item != null)
{
var progress = GetProgressInfo(e.OldMediaInfo, streamInfo);
@@ -151,9 +151,9 @@ namespace MediaBrowser.Dlna.PlayTo
ReportPlaybackStopped(e.OldMediaInfo, streamInfo, positionTicks);
}
- streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager);
+ streamInfo = await StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (streamInfo.Item == null) return;
-
+
var newItemProgress = GetProgressInfo(e.NewMediaInfo, streamInfo);
await _sessionManager.OnPlaybackStart(newItemProgress).ConfigureAwait(false);
@@ -168,7 +168,8 @@ namespace MediaBrowser.Dlna.PlayTo
{
try
{
- var streamInfo = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
+ var streamInfo = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager)
+ .ConfigureAwait(false);
if (streamInfo.Item == null) return;
@@ -230,7 +231,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
try
{
- var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
+ var info = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (info.Item != null)
{
@@ -249,7 +250,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
try
{
- var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
+ var info = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (info.Item != null)
{
@@ -377,7 +378,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (media != null)
{
- var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
+ var info = await StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (info.Item != null && !EnableClientSideSeek(info))
{
@@ -470,7 +471,7 @@ namespace MediaBrowser.Dlna.PlayTo
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
-
+
var hasMediaSources = item as IHasMediaSources;
var mediaSources = hasMediaSources != null
? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
@@ -739,7 +740,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (media != null)
{
- var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
+ var info = await StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (info.Item != null)
{
@@ -765,7 +766,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (media != null)
{
- var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
+ var info = await StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false);
if (info.Item != null)
{
@@ -840,7 +841,7 @@ namespace MediaBrowser.Dlna.PlayTo
return null;
}
- public static StreamParams ParseFromUrl(string url, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
+ public static async Task<StreamParams> ParseFromUrl(string url, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
{
var request = new StreamParams
{
@@ -906,11 +907,9 @@ namespace MediaBrowser.Dlna.PlayTo
var hasMediaSources = request.Item as IHasMediaSources;
- request.MediaSource = hasMediaSources == null ?
- null :
- mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).Result;
-
-
+ request.MediaSource = hasMediaSources == null
+ ? null
+ : (await mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).ConfigureAwait(false));
return request;
}
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index bbb9bf6de..cd9a7b1f0 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -101,6 +101,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
var uri = new Uri(location);
+ _logger.Debug("Attempting to create PlayToController from location {0}", location);
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
if (device.RendererCommands == null)
@@ -112,6 +113,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
+ _logger.Debug("Logging session activity from location {0}", location);
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
.ConfigureAwait(false);
diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
index 3bff80a70..202ea76fb 100644
--- a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs
@@ -54,21 +54,21 @@ namespace MediaBrowser.Dlna.Profiles
new DirectPlayProfile
{
Container = "ts",
- VideoCodec = "h264,hevc",
+ VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
- VideoCodec = "h264,hevc",
+ VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
- VideoCodec = "h264,mpeg4,hevc",
+ VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
@@ -189,6 +189,15 @@ namespace MediaBrowser.Dlna.Profiles
}
}
};
+
+ SubtitleProfiles = new[]
+ {
+ new SubtitleProfile
+ {
+ Format = "srt",
+ Method = SubtitleDeliveryMethod.External
+ }
+ };
}
}
}
diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
index 1b06e1d6a..c117d030f 100644
--- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
@@ -21,8 +21,8 @@ namespace MediaBrowser.Dlna.Profiles
new HttpHeaderInfo
{
Name = "User-Agent",
- Value = @"SEC_",
- Match = HeaderMatchType.Substring
+ Value = @".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*.",
+ Match = HeaderMatchType.Regex
}
}
};
diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
index 404bbbb20..1147aa299 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
@@ -35,9 +35,9 @@
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264,hevc" type="Video" />
- <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264,hevc" type="Video" />
- <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3" videoCodec="h264,mpeg4,hevc" type="Video" />
+ <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
+ <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3" videoCodec="h264,mpeg4" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
@@ -77,5 +77,7 @@
</CodecProfile>
</CodecProfiles>
<ResponseProfiles />
- <SubtitleProfiles />
+ <SubtitleProfiles>
+ <SubtitleProfile format="srt" method="External" />
+ </SubtitleProfiles>
</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
index b09c25afa..967538bdf 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
@@ -4,7 +4,7 @@
<Identification>
<ModelUrl>samsung.com</ModelUrl>
<Headers>
- <HttpHeaderInfo name="User-Agent" value="SEC_" match="Substring" />
+ <HttpHeaderInfo name="User-Agent" value=".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*." match="Regex" />
</Headers>
</Identification>
<Manufacturer>Emby</Manufacturer>
diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
index 1eda79f02..68768745e 100644
--- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
@@ -61,7 +61,7 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e)
+ async void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e)
{
string nts;
e.Headers.TryGetValue("NTS", out nts);
@@ -78,7 +78,7 @@ namespace MediaBrowser.Dlna.Ssdp
{
if (e.LocalEndPoint == null)
{
- var ip = _appHost.LocalIpAddresses.FirstOrDefault(i => !IPAddress.IsLoopback(i));
+ var ip = (await _appHost.GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !IPAddress.IsLoopback(i));
if (ip != null)
{
e.LocalEndPoint = new IPEndPoint(ip, 0);
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index 2d5225344..cd1575fa5 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
@@ -16,7 +17,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
}
- protected override string GetCommandLineArguments(EncodingJob state)
+ protected override Task<string> GetCommandLineArguments(EncodingJob state)
{
var audioTranscodeParams = new List<string>();
@@ -61,7 +62,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
vn = " -vn";
}
- return string.Format("{0} {1}{6}{7} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{8} -y \"{5}\"",
+ var result = string.Format("{0} {1}{6}{7} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{8} -y \"{5}\"",
inputModifier,
GetInputArgument(state),
threads,
@@ -71,6 +72,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
albumCoverInput,
mapArgs,
metadata).Trim();
+
+ return Task.FromResult(result);
}
protected override string GetOutputFileExtension(EncodingJob state)
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index dd227952e..22f739801 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -42,8 +42,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
IFileSystem fileSystem,
IIsoManager isoManager,
ILibraryManager libraryManager,
- ISessionManager sessionManager,
- ISubtitleEncoder subtitleEncoder,
+ ISessionManager sessionManager,
+ ISubtitleEncoder subtitleEncoder,
IMediaSourceManager mediaSourceManager)
{
MediaEncoder = mediaEncoder;
@@ -71,7 +71,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false);
- var commandLineArgs = GetCommandLineArguments(encodingJob);
+ var commandLineArgs = await GetCommandLineArguments(encodingJob).ConfigureAwait(false);
var process = new Process
{
@@ -131,7 +131,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
cancellationToken.Register(() => Cancel(process, encodingJob));
-
+
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
process.BeginOutputReadLine();
@@ -139,7 +139,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);
// Wait for the file to exist before proceeeding
- while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
+ while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
{
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
@@ -264,11 +264,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
}
- protected abstract string GetCommandLineArguments(EncodingJob job);
+ protected abstract Task<string> GetCommandLineArguments(EncodingJob job);
private string GetOutputFilePath(EncodingJob state)
{
- var folder = string.IsNullOrWhiteSpace(state.Options.OutputDirectory) ?
+ var folder = string.IsNullOrWhiteSpace(state.Options.OutputDirectory) ?
ConfigurationManager.ApplicationPaths.TranscodingTempPath :
state.Options.OutputDirectory;
@@ -363,7 +363,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- return null;
+ return null;
}
if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
@@ -536,7 +536,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <param name="state">The state.</param>
/// <param name="outputVideoCodec">The output video codec.</param>
/// <returns>System.String.</returns>
- protected string GetGraphicalSubtitleParam(EncodingJob state, string outputVideoCodec)
+ protected async Task<string> GetGraphicalSubtitleParam(EncodingJob state, string outputVideoCodec)
{
var outputSizeParam = string.Empty;
@@ -545,7 +545,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Add resolution params, if specified
if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue)
{
- outputSizeParam = GetOutputSizeParam(state, outputVideoCodec).TrimEnd('"');
+ outputSizeParam = await GetOutputSizeParam(state, outputVideoCodec).ConfigureAwait(false);
+ outputSizeParam = outputSizeParam.TrimEnd('"');
outputSizeParam = "," + outputSizeParam.Substring(outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase));
}
@@ -858,7 +859,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <param name="outputVideoCodec">The output video codec.</param>
/// <param name="allowTimeStampCopy">if set to <c>true</c> [allow time stamp copy].</param>
/// <returns>System.String.</returns>
- protected string GetOutputSizeParam(EncodingJob state,
+ protected async Task<string> GetOutputSizeParam(EncodingJob state,
string outputVideoCodec,
bool allowTimeStampCopy = true)
{
@@ -935,7 +936,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.Options.SubtitleMethod == SubtitleDeliveryMethod.Encode)
{
- var subParam = GetTextSubtitleParam(state);
+ var subParam = await GetTextSubtitleParam(state).ConfigureAwait(false);
filters.Add(subParam);
@@ -958,7 +959,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
- protected string GetTextSubtitleParam(EncodingJob state)
+ protected async Task<string> GetTextSubtitleParam(EncodingJob state)
{
var seconds = Math.Round(TimeSpan.FromTicks(state.Options.StartTimeTicks ?? 0).TotalSeconds);
@@ -970,7 +971,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
{
- var charenc = SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).Result;
+ var charenc = await SubtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).ConfigureAwait(false);
if (!string.IsNullOrEmpty(charenc))
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 1544a78b6..7fe7facdf 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (videoRequest != null)
{
state.OutputVideoCodec = state.Options.VideoCodec;
- state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream);
+ state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);
if (state.OutputVideoBitrate.HasValue)
{
@@ -396,7 +396,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return request.AudioChannels;
}
- private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream)
+ private int? GetVideoBitrateParamValue(EncodingJobOptions request, MediaStream videoStream, string outputVideoCodec)
{
var bitrate = request.VideoBitRate;
@@ -421,6 +421,18 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ if (bitrate.HasValue)
+ {
+ var inputVideoCodec = videoStream == null ? null : videoStream.Codec;
+ bitrate = ResolutionNormalizer.ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
+
+ // If a max bitrate was requested, don't let the scaled bitrate exceed it
+ if (request.VideoBitRate.HasValue)
+ {
+ bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ }
+ }
+
return bitrate;
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 399fdead9..f8321f6cd 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -21,6 +21,9 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -64,8 +67,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
public string FFProbePath { get; private set; }
- public string Version { get; private set; }
-
protected readonly IServerConfigurationManager ConfigurationManager;
protected readonly IFileSystem FileSystem;
protected readonly ILiveTvManager LiveTvManager;
@@ -77,12 +78,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
protected readonly Func<IMediaSourceManager> MediaSourceManager;
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
+ private readonly bool _hasExternalEncoder;
- public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager)
+ public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
- Version = version;
ConfigurationManager = configurationManager;
FileSystem = fileSystem;
LiveTvManager = liveTvManager;
@@ -94,6 +95,138 @@ namespace MediaBrowser.MediaEncoding.Encoder
MediaSourceManager = mediaSourceManager;
FFProbePath = ffProbePath;
FFMpegPath = ffMpegPath;
+
+ _hasExternalEncoder = hasExternalEncoder;
+ }
+
+ public void Init()
+ {
+ ConfigureEncoderPaths();
+
+ if (_hasExternalEncoder)
+ {
+ LogPaths();
+ return;
+ }
+
+ // If the path was passed in, save it into config now.
+ var encodingOptions = GetEncodingOptions();
+ var appPath = encodingOptions.EncoderAppPath;
+ if (!string.IsNullOrWhiteSpace(FFMpegPath) && !string.Equals(FFMpegPath, appPath, StringComparison.Ordinal))
+ {
+ encodingOptions.EncoderAppPath = FFMpegPath;
+ ConfigurationManager.SaveConfiguration("encoding", encodingOptions);
+ }
+ }
+
+ public async Task UpdateEncoderPath(string path)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (!File.Exists(path) && !Directory.Exists(path))
+ {
+ throw new ResourceNotFoundException();
+ }
+
+ var newPaths = GetEncoderPaths(path);
+ if (string.IsNullOrWhiteSpace(newPaths.Item1))
+ {
+ throw new ResourceNotFoundException("ffmpeg not found");
+ }
+ if (string.IsNullOrWhiteSpace(newPaths.Item2))
+ {
+ throw new ResourceNotFoundException("ffprobe not found");
+ }
+
+ var config = GetEncodingOptions();
+ config.EncoderAppPath = path;
+ ConfigurationManager.SaveConfiguration("encoding", config);
+
+ Init();
+ }
+
+ private void ConfigureEncoderPaths()
+ {
+ if (_hasExternalEncoder)
+ {
+ return;
+ }
+
+ var appPath = GetEncodingOptions().EncoderAppPath;
+
+ if (string.IsNullOrWhiteSpace(appPath))
+ {
+ appPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg");
+ }
+ var newPaths = GetEncoderPaths(appPath);
+
+ if (!string.IsNullOrWhiteSpace(newPaths.Item1) && !string.IsNullOrWhiteSpace(newPaths.Item2))
+ {
+ FFMpegPath = newPaths.Item1;
+ FFProbePath = newPaths.Item2;
+ }
+
+ LogPaths();
+ }
+
+ private Tuple<string, string> GetEncoderPaths(string configuredPath)
+ {
+ var appPath = configuredPath;
+
+ if (!string.IsNullOrWhiteSpace(appPath))
+ {
+ if (Directory.Exists(appPath))
+ {
+ return GetPathsFromDirectory(appPath);
+ }
+
+ if (File.Exists(appPath))
+ {
+ return new Tuple<string, string>(appPath, GetProbePathFromEncoderPath(appPath));
+ }
+ }
+
+ return new Tuple<string, string>(null, null);
+ }
+
+ private Tuple<string,string> GetPathsFromDirectory(string path)
+ {
+ // Since we can't predict the file extension, first try directly within the folder
+ // If that doesn't pan out, then do a recursive search
+ var files = Directory.GetFiles(path);
+
+ var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase));
+ var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase));
+
+ if (string.IsNullOrWhiteSpace(ffmpegPath) || !File.Exists(ffmpegPath))
+ {
+ files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
+
+ ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase));
+ ffprobePath = GetProbePathFromEncoderPath(ffmpegPath);
+ }
+
+ return new Tuple<string, string>(ffmpegPath, ffprobePath);
+ }
+
+ private string GetProbePathFromEncoderPath(string appPath)
+ {
+ return Directory.GetFiles(Path.GetDirectoryName(appPath))
+ .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase));
+ }
+
+ private void LogPaths()
+ {
+ _logger.Info("FFMpeg: {0}", FFMpegPath ?? "not found");
+ _logger.Info("FFProbe: {0}", FFProbePath ?? "not found");
+ }
+
+ private EncodingOptions GetEncodingOptions()
+ {
+ return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
}
private List<string> _encoders = new List<string>();
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 3ab55168d..82a966821 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.IO;
+using System.Threading.Tasks;
using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
@@ -17,7 +18,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
}
- protected override string GetCommandLineArguments(EncodingJob state)
+ protected override async Task<string> GetCommandLineArguments(EncodingJob state)
{
// Get the output codec name
var videoCodec = EncodingJobFactory.GetVideoEncoder(state, GetEncodingOptions());
@@ -36,12 +37,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
var inputModifier = GetInputModifier(state);
+ var videoArguments = await GetVideoArguments(state, videoCodec).ConfigureAwait(false);
+
return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
inputModifier,
GetInputArgument(state),
keyFrame,
GetMapArgs(state),
- GetVideoArguments(state, videoCodec),
+ videoArguments,
threads,
GetAudioArguments(state),
format,
@@ -55,7 +58,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <param name="state">The state.</param>
/// <param name="videoCodec">The video codec.</param>
/// <returns>System.String.</returns>
- private string GetVideoArguments(EncodingJob state, string videoCodec)
+ private async Task<string> GetVideoArguments(EncodingJob state, string videoCodec)
{
var args = "-codec:v:0 " + videoCodec;
@@ -91,7 +94,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Add resolution params, if specified
if (!hasGraphicalSubs)
{
- args += GetOutputSizeParam(state, videoCodec);
+ args += await GetOutputSizeParam(state, videoCodec).ConfigureAwait(false);
}
var qualityParam = GetVideoQualityParam(state, videoCodec);
@@ -104,7 +107,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// This is for internal graphical subs
if (hasGraphicalSubs)
{
- args += GetGraphicalSubtitleParam(state, videoCodec);
+ args += await GetGraphicalSubtitleParam(state, videoCodec).ConfigureAwait(false);
}
return args;
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 44c69d4c1..44a0f264d 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -408,7 +408,9 @@ namespace MediaBrowser.MediaEncoding.Probing
Level = streamInfo.level,
Index = streamInfo.index,
PixelFormat = streamInfo.pix_fmt,
- NalLengthSize = streamInfo.nal_length_size
+ NalLengthSize = streamInfo.nal_length_size,
+ TimeBase = streamInfo.time_base,
+ CodecTimeBase = streamInfo.codec_time_base
};
if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) ||
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index f759ffeae..0de9fb519 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -599,9 +599,6 @@
<Compile Include="..\MediaBrowser.Model\Entities\Video3DFormat.cs">
<Link>Entities\Video3DFormat.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Entities\VideoSize.cs">
- <Link>Entities\VideoSize.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Entities\VideoType.cs">
<Link>Entities\VideoType.cs</Link>
</Compile>
@@ -1139,6 +1136,9 @@
<Compile Include="..\MediaBrowser.Model\Sync\SyncTarget.cs">
<Link>Sync\SyncTarget.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\System\Architecture.cs">
+ <Link>System\Architecture.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\System\LogFile.cs">
<Link>System\LogFile.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 05bbeb50e..fe0b3bcae 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -573,9 +573,6 @@
<Compile Include="..\MediaBrowser.Model\Entities\Video3DFormat.cs">
<Link>Entities\Video3DFormat.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Entities\VideoSize.cs">
- <Link>Entities\VideoSize.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Entities\VideoType.cs">
<Link>Entities\VideoType.cs</Link>
</Compile>
@@ -1104,6 +1101,9 @@
<Compile Include="..\MediaBrowser.Model\Sync\SyncTarget.cs">
<Link>Sync\SyncTarget.cs</Link>
</Compile>
+ <Compile Include="..\MediaBrowser.Model\System\Architecture.cs">
+ <Link>System\Architecture.cs</Link>
+ </Compile>
<Compile Include="..\MediaBrowser.Model\System\LogFile.cs">
<Link>System\LogFile.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/Channels/ChannelFolderType.cs b/MediaBrowser.Model/Channels/ChannelFolderType.cs
index 9261cb5cd..7c97afd02 100644
--- a/MediaBrowser.Model/Channels/ChannelFolderType.cs
+++ b/MediaBrowser.Model/Channels/ChannelFolderType.cs
@@ -6,6 +6,12 @@ namespace MediaBrowser.Model.Channels
MusicAlbum = 1,
- PhotoAlbum = 2
+ PhotoAlbum = 2,
+
+ MusicArtist = 3,
+
+ Series = 4,
+
+ Season = 5
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index d33cf5577..91d28a296 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -9,6 +9,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableThrottling { get; set; }
public int ThrottleDelaySeconds { get; set; }
public string HardwareAccelerationType { get; set; }
+ public string EncoderAppPath { get; set; }
public EncodingOptions()
{
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index e89aafaca..e4c17ff2b 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value><c>true</c> if [enable case sensitive item ids]; otherwise, <c>false</c>.</value>
public bool EnableCaseSensitiveItemIds { get; set; }
-
+
/// <summary>
/// Gets or sets the metadata path.
/// </summary>
@@ -155,7 +155,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value>The dashboard source path.</value>
public string DashboardSourcePath { get; set; }
-
+
/// <summary>
/// Gets or sets the image saving convention.
/// </summary>
@@ -199,16 +199,22 @@ namespace MediaBrowser.Model.Configuration
public bool EnableStandaloneMusicKeys { get; set; }
public bool EnableLocalizedGuids { get; set; }
public bool EnableFolderView { get; set; }
+ public bool EnableGroupingIntoCollections { get; set; }
+ public bool DisplaySpecialsWithinSeasons { get; set; }
+ public bool DisplayCollectionsView { get; set; }
+ public string[] LocalNetworkAddresses { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
public ServerConfiguration()
{
+ LocalNetworkAddresses = new string[] { };
Migrations = new string[] { };
EnableCustomPathSubFolders = true;
EnableLocalizedGuids = true;
+ DisplaySpecialsWithinSeasons = true;
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
index 8a412ac2c..ed18fed65 100644
--- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
+++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
@@ -56,5 +56,25 @@ namespace MediaBrowser.Model.Dlna
MaxHeight = maxHeight
};
}
+
+ private static double GetVideoBitrateScaleFactor(string codec)
+ {
+ if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
+ {
+ return .5;
+ }
+ return 1;
+ }
+
+ public static int ScaleBitrate(int bitrate, string inputVideoCodec, string outputVideoCodec)
+ {
+ var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
+ var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec);
+ var scaleFactor = outputScaleFactor/inputScaleFactor;
+ var newBitrate = scaleFactor*bitrate;
+
+ return Convert.ToInt32(newBitrate);
+ }
}
}
diff --git a/MediaBrowser.Model/Dto/ItemCounts.cs b/MediaBrowser.Model/Dto/ItemCounts.cs
index a3a00c341..07ddfa1ac 100644
--- a/MediaBrowser.Model/Dto/ItemCounts.cs
+++ b/MediaBrowser.Model/Dto/ItemCounts.cs
@@ -60,5 +60,6 @@
/// </summary>
/// <value>The book count.</value>
public int BookCount { get; set; }
+ public int ItemCount { get; set; }
}
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 6a3c08425..af7a034fe 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -36,6 +36,9 @@ namespace MediaBrowser.Model.Entities
/// <value>The comment.</value>
public string Comment { get; set; }
+ public string TimeBase { get; set; }
+ public string CodecTimeBase { get; set; }
+
public string Title { get; set; }
public string DisplayTitle
@@ -72,15 +75,12 @@ namespace MediaBrowser.Model.Entities
{
attributes.Add(StringHelper.ToStringCultureInvariant(Channels.Value) + " ch");
}
-
- string name = string.Join(" ", attributes.ToArray());
-
if (IsDefault)
{
- name += " (D)";
+ attributes.Add("Default");
}
- return name;
+ return string.Join(" ", attributes.ToArray());
}
if (Type == MediaStreamType.Subtitle)
@@ -91,27 +91,17 @@ namespace MediaBrowser.Model.Entities
{
attributes.Add(StringHelper.FirstToUpper(Language));
}
- if (!string.IsNullOrEmpty(Codec))
- {
- attributes.Add(Codec);
- }
-
- string name = string.Join(" ", attributes.ToArray());
-
if (IsDefault)
{
- name += " (D)";
+ attributes.Add("Default");
}
if (IsForced)
{
- name += " (F)";
+ attributes.Add("Forced");
}
- if (IsExternal)
- {
- name += " (EXT)";
- }
+ string name = string.Join(" ", attributes.ToArray());
return name;
}
diff --git a/MediaBrowser.Model/Entities/MediaUrl.cs b/MediaBrowser.Model/Entities/MediaUrl.cs
index 24e3b1492..2e17bba8a 100644
--- a/MediaBrowser.Model/Entities/MediaUrl.cs
+++ b/MediaBrowser.Model/Entities/MediaUrl.cs
@@ -5,6 +5,5 @@ namespace MediaBrowser.Model.Entities
{
public string Url { get; set; }
public string Name { get; set; }
- public VideoSize? VideoSize { get; set; }
}
}
diff --git a/MediaBrowser.Model/Entities/VideoSize.cs b/MediaBrowser.Model/Entities/VideoSize.cs
deleted file mode 100644
index 0100f3b90..000000000
--- a/MediaBrowser.Model/Entities/VideoSize.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace MediaBrowser.Model.Entities
-{
- public enum VideoSize
- {
- StandardDefinition,
- HighDefinition
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 9e34ff042..242a2d24e 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -1,4 +1,6 @@
using System.Collections.Generic;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.LiveTv
{
@@ -73,17 +75,33 @@ namespace MediaBrowser.Model.LiveTv
public string[] EnabledTuners { get; set; }
public bool EnableAllTuners { get; set; }
- public string[] NewsGenres { get; set; }
- public string[] SportsGenres { get; set; }
- public string[] KidsGenres { get; set; }
+ public string[] NewsCategories { get; set; }
+ public string[] SportsCategories { get; set; }
+ public string[] KidsCategories { get; set; }
+ public string[] MovieCategories { get; set; }
+ public NameValuePair[] ChannelMappings { get; set; }
public ListingsProviderInfo()
{
- NewsGenres = new string[] { "news" };
- SportsGenres = new string[] { "sports", "basketball", "baseball", "football" };
- KidsGenres = new string[] { "kids", "family", "children" };
+ NewsCategories = new string[] { "news", "journalism", "documentary", "current affairs" };
+ SportsCategories = new string[] { "sports", "basketball", "baseball", "football" };
+ KidsCategories = new string[] { "kids", "family", "children", "childrens", "disney" };
+ MovieCategories = new string[] { "movie" };
EnabledTuners = new string[] { };
EnableAllTuners = true;
+ ChannelMappings = new NameValuePair[] {};
+ }
+
+ public string GetMappedChannel(string channelNumber)
+ {
+ foreach (NameValuePair mapping in ChannelMappings)
+ {
+ if (StringHelper.EqualsIgnoreCase(mapping.Name, channelNumber))
+ {
+ return mapping.Value;
+ }
+ }
+ return channelNumber;
}
}
}
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index 0cf997602..923d303f8 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -70,5 +70,12 @@ namespace MediaBrowser.Model.LiveTv
public bool? EnableImages { get; set; }
public int? ImageTypeLimit { get; set; }
public ImageType[] EnableImageTypes { get; set; }
+
+ public bool EnableTotalRecordCount { get; set; }
+
+ public RecordingQuery()
+ {
+ EnableTotalRecordCount = true;
+ }
}
}
diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs
index e6ceff530..87b6b89ac 100644
--- a/MediaBrowser.Model/LiveTv/TimerQuery.cs
+++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs
@@ -13,5 +13,7 @@
/// </summary>
/// <value>The series timer identifier.</value>
public string SeriesTimerId { get; set; }
+
+ public bool? IsActive { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 522b7d38d..e54273b84 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -227,7 +227,6 @@
<Compile Include="Entities\ProviderIdsExtensions.cs" />
<Compile Include="Entities\ScrollDirection.cs" />
<Compile Include="Entities\SortOrder.cs" />
- <Compile Include="Entities\VideoSize.cs" />
<Compile Include="Events\GenericEventArgs.cs" />
<Compile Include="Extensions\DoubleHelper.cs" />
<Compile Include="Extensions\IHasPropertyChangedEvent.cs" />
@@ -396,6 +395,7 @@
<Compile Include="Sync\SyncProfileOption.cs" />
<Compile Include="Sync\SyncQualityOption.cs" />
<Compile Include="Sync\SyncTarget.cs" />
+ <Compile Include="System\Architecture.cs" />
<Compile Include="System\LogFile.cs" />
<Compile Include="System\PublicSystemInfo.cs" />
<Compile Include="Updates\CheckForUpdateResult.cs" />
diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs
index 9c2926b54..6f4ebd0c5 100644
--- a/MediaBrowser.Model/Querying/ItemSortBy.cs
+++ b/MediaBrowser.Model/Querying/ItemSortBy.cs
@@ -85,5 +85,6 @@ namespace MediaBrowser.Model.Querying
public const string GameSystem = "GameSystem";
public const string IsFavoriteOrLiked = "IsFavoriteOrLiked";
public const string DateLastContentAdded = "DateLastContentAdded";
+ public const string SeriesDatePlayed = "SeriesDatePlayed";
}
}
diff --git a/MediaBrowser.Model/System/Architecture.cs b/MediaBrowser.Model/System/Architecture.cs
new file mode 100644
index 000000000..09eedddc1
--- /dev/null
+++ b/MediaBrowser.Model/System/Architecture.cs
@@ -0,0 +1,9 @@
+namespace MediaBrowser.Model.System
+{
+ public enum Architecture
+ {
+ X86 = 0,
+ X64 = 1,
+ Arm = 2
+ }
+}
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index 6b54a90d4..868d9dc28 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -152,6 +152,10 @@ namespace MediaBrowser.Model.System
/// <value><c>true</c> if [supports automatic run at startup]; otherwise, <c>false</c>.</value>
public bool SupportsAutoRunAtStartup { get; set; }
+ public bool HasExternalEncoder { get; set; }
+
+ public Architecture SystemArchitecture { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="SystemInfo" /> class.
/// </summary>
diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs
index 6e2cd77eb..88811c850 100644
--- a/MediaBrowser.Providers/Chapters/ChapterManager.cs
+++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs
@@ -259,7 +259,7 @@ namespace MediaBrowser.Providers.Chapters
return _itemRepo.GetChapters(new Guid(itemId));
}
- public Task SaveChapters(string itemId, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken)
{
return _itemRepo.SaveChapters(new Guid(itemId), chapters, cancellationToken);
}
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index 3b3065893..a6b6de7e5 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -326,8 +326,7 @@ namespace MediaBrowser.Providers.Movies
hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
{
Url = string.Format("https://www.youtube.com/watch?v={0}", i.source),
- Name = i.name,
- VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition
+ Name = i.name
}).ToList();
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
index ceb41178e..ab2cd3bed 100644
--- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
internal static string AcceptHeader = "application/json,image/*";
-
+
private readonly ILogger _logger;
private readonly IJsonSerializer _json;
private readonly ILibraryManager _libraryManager;
@@ -54,6 +54,11 @@ namespace MediaBrowser.Providers.Movies
var name = idInfo.Name;
var year = idInfo.Year;
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ return new List<RemoteSearchResult>();
+ }
+
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
@@ -73,7 +78,7 @@ namespace MediaBrowser.Providers.Movies
//var searchType = item is BoxSet ? "collection" : "movie";
var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);
-
+
if (results.Count == 0)
{
//try in english if wasn't before
@@ -123,19 +128,23 @@ namespace MediaBrowser.Providers.Movies
});
}
- private async Task<List<RemoteSearchResult>> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
+ private Task<List<RemoteSearchResult>> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
{
switch (type)
{
case "tv":
- return await GetSearchResultsTv(name, year, language, baseImageUrl, cancellationToken);
+ return GetSearchResultsTv(name, year, language, baseImageUrl, cancellationToken);
default:
- return await GetSearchResultsGeneric(name, type, year, language, baseImageUrl, cancellationToken);
+ return GetSearchResultsGeneric(name, type, year, language, baseImageUrl, cancellationToken);
}
}
private async Task<List<RemoteSearchResult>> GetSearchResultsGeneric(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
{
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("name");
+ }
var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type);
@@ -189,6 +198,11 @@ namespace MediaBrowser.Providers.Movies
private async Task<List<RemoteSearchResult>> GetSearchResultsTv(string name, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
{
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("name");
+ }
+
var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, "tv");
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index 6e57b4022..1710ec2b0 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -14,6 +14,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Music
{
@@ -24,14 +25,16 @@ namespace MediaBrowser.Providers.Music
private readonly IHttpClient _httpClient;
private readonly IApplicationHost _appHost;
private readonly ILogger _logger;
+ private readonly IJsonSerializer _json;
public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org";
- public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger)
+ public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json)
{
_httpClient = httpClient;
_appHost = appHost;
_logger = logger;
+ _json = json;
Current = this;
}
@@ -44,7 +47,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrEmpty(releaseId))
{
- url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=reid:{0}", releaseId);
+ url = string.Format("/ws/2/release/?query=reid:{0}", releaseId);
}
else
{
@@ -52,7 +55,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
{
- url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(searchInfo.Name),
artistMusicBrainzId);
}
@@ -60,7 +63,7 @@ namespace MediaBrowser.Providers.Music
{
isNameSearch = true;
- url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(searchInfo.Name),
WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
}
@@ -199,57 +202,86 @@ namespace MediaBrowser.Providers.Music
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
{
- var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ var url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(albumName),
artistId);
var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
- return GetReleaseResult(doc);
+ return ReleaseResult.Parse(doc);
}
private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken)
{
- var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ var url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(albumName),
WebUtility.UrlEncode(artistName));
var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
- return GetReleaseResult(doc);
+ return ReleaseResult.Parse(doc);
}
- private ReleaseResult GetReleaseResult(XmlDocument doc)
+ private class ReleaseResult
{
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", MusicBrainzBaseUrl + "/ns/mmd-2.0#");
+ public string ReleaseId;
+ public string ReleaseGroupId;
- var result = new ReleaseResult
+ public static ReleaseResult Parse(XmlDocument doc)
{
+ var docElem = doc.DocumentElement;
- };
+ if (docElem == null)
+ {
+ return new ReleaseResult();
+ }
- var releaseIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/@id", ns);
+ var releaseList = docElem.FirstChild;
+ if (releaseList == null)
+ {
+ return new ReleaseResult();
+ }
- if (releaseIdNode != null)
- {
- result.ReleaseId = releaseIdNode.Value;
- }
+ var nodes = releaseList.ChildNodes;
+ string releaseId = null;
+ string releaseGroupId = null;
- var releaseGroupIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/mb:release-group/@id", ns);
+ if (nodes != null)
+ {
+ foreach (var node in nodes.Cast<XmlNode>())
+ {
+ if (string.Equals(node.Name, "release", StringComparison.OrdinalIgnoreCase))
+ {
+ releaseId = node.Attributes["id"].Value;
+ releaseGroupId = GetReleaseGroupIdFromReleaseNode(node);
+ break;
+ }
+ }
+ }
- if (releaseGroupIdNode != null)
- {
- result.ReleaseGroupId = releaseGroupIdNode.Value;
+ return new ReleaseResult
+ {
+ ReleaseId = releaseId,
+ ReleaseGroupId = releaseGroupId
+ };
}
- return result;
- }
+ private static string GetReleaseGroupIdFromReleaseNode(XmlNode node)
+ {
+ var subNodes = node.ChildNodes;
+ if (subNodes != null)
+ {
+ foreach (var subNode in subNodes.Cast<XmlNode>())
+ {
+ if (string.Equals(subNode.Name, "release-group", StringComparison.OrdinalIgnoreCase))
+ {
+ return subNode.Attributes["id"].Value;
+ }
+ }
+ }
- private class ReleaseResult
- {
- public string ReleaseId;
- public string ReleaseGroupId;
+ return null;
+ }
}
/// <summary>
@@ -260,15 +292,36 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{System.String}.</returns>
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
{
- var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release-group/?query=reid:{0}", releaseEntryId);
+ var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId);
var doc = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false);
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", MusicBrainzBaseUrl + "/ns/mmd-2.0#");
- var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
+ var docElem = doc.DocumentElement;
+
+ if (docElem == null)
+ {
+ return null;
+ }
- return node != null ? node.Value : null;
+ var releaseList = docElem.FirstChild;
+ if (releaseList == null)
+ {
+ return null;
+ }
+
+ var nodes = releaseList.ChildNodes;
+
+ if (nodes != null)
+ {
+ foreach (var node in nodes.Cast<XmlNode>())
+ {
+ if (string.Equals(node.Name, "release-group", StringComparison.OrdinalIgnoreCase))
+ {
+ return node.Attributes["id"].Value;
+ }
+ }
+ }
+ return null;
}
/// <summary>
@@ -276,6 +329,66 @@ namespace MediaBrowser.Providers.Music
/// </summary>
private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1);
+ private long _lastMbzUrlQueryTicks = 0;
+ private List<MbzUrl> _mbzUrls = null;
+ private MbzUrl _chosenUrl;
+
+ private async Task<MbzUrl> GetMbzUrl()
+ {
+ if (_chosenUrl == null || _mbzUrls == null || (DateTime.UtcNow.Ticks - _lastMbzUrlQueryTicks) > TimeSpan.FromHours(12).Ticks)
+ {
+ var urls = await RefreshMzbUrls().ConfigureAwait(false);
+
+ if (urls.Count > 1)
+ {
+ _chosenUrl = urls[new Random().Next(0, urls.Count)];
+ }
+ else
+ {
+ _chosenUrl = urls[0];
+ }
+ }
+
+ return _chosenUrl;
+ }
+
+ private async Task<List<MbzUrl>> RefreshMzbUrls()
+ {
+ List<MbzUrl> list;
+
+ try
+ {
+ var options = new HttpRequestOptions
+ {
+ Url = "https://mb3admin.com/admin/service/standards/musicBrainzUrls",
+ UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion
+ };
+
+ using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
+ {
+ list = _json.DeserializeFromStream<List<MbzUrl>>(stream);
+ }
+ _lastMbzUrlQueryTicks = DateTime.UtcNow.Ticks;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting music brainz info", ex);
+
+ list = new List<MbzUrl>
+ {
+ new MbzUrl
+ {
+ url = MusicBrainzBaseUrl,
+ throttleMs = 1000
+ }
+ };
+ }
+
+ _mbzUrls = list.ToList();
+
+ return list;
+ }
+
/// <summary>
/// Gets the music brainz response.
/// </summary>
@@ -285,9 +398,15 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{XmlDocument}.</returns>
internal async Task<XmlDocument> GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken)
{
- // MusicBrainz is extremely adamant about limiting to one request per second
+ var urlInfo = await GetMbzUrl().ConfigureAwait(false);
- await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
+ if (urlInfo.throttleMs > 0)
+ {
+ // MusicBrainz is extremely adamant about limiting to one request per second
+ await Task.Delay(urlInfo.throttleMs, cancellationToken).ConfigureAwait(false);
+ }
+
+ url = urlInfo.url.TrimEnd('/') + url;
var doc = new XmlDocument();
@@ -319,5 +438,11 @@ namespace MediaBrowser.Providers.Music
{
throw new NotImplementedException();
}
+
+ internal class MbzUrl
+ {
+ public string url { get; set; }
+ public int throttleMs { get; set; }
+ }
}
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 86563b2b9..88635bf06 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(musicBrainzId))
{
- var url = string.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=arid:{0}", musicBrainzId);
+ var url = string.Format("/ws/2/artist/?query=arid:{0}", musicBrainzId);
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken)
.ConfigureAwait(false);
@@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.Music
// They seem to throw bad request failures on any term with a slash
var nameToSearch = searchInfo.Name.Replace('/', ' ');
- var url = String.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
+ var url = String.Format("/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
@@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Music
if (HasDiacritics(searchInfo.Name))
{
// Try again using the search with accent characters url
- url = String.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
+ url = String.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
@@ -62,9 +62,6 @@ namespace MediaBrowser.Providers.Music
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
{
- //var ns = new XmlNamespaceManager(doc.NameTable);
- //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
-
var list = new List<RemoteSearchResult>();
var docElem = doc.DocumentElement;
@@ -96,7 +93,7 @@ namespace MediaBrowser.Providers.Music
{
if (string.Equals(child.Name, "name", StringComparison.OrdinalIgnoreCase))
{
- name = node.InnerText;
+ name = child.InnerText;
break;
}
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index 4056073f2..397107c74 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Serialization;
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -114,6 +115,106 @@ namespace MediaBrowser.Providers.Omdb
ParseAdditionalMetadata(item, result);
}
+ public async Task<bool> FetchEpisodeData(BaseItem item, int episodeNumber, int seasonNumber, string imdbId, string language, string country, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrWhiteSpace(imdbId))
+ {
+ throw new ArgumentNullException("imdbId");
+ }
+
+ var seasonResult = await GetSeasonRootObject(imdbId, seasonNumber, cancellationToken);
+
+ RootObject result = null;
+
+ foreach (var episode in seasonResult.Episodes)
+ {
+ if (episode.Episode == episodeNumber)
+ {
+ result = episode;
+ break;
+ }
+ }
+
+ if (result == null)
+ {
+ return false;
+ }
+
+
+ // Only take the name and rating if the user's language is set to english, since Omdb has no localization
+ if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
+ {
+ item.Name = result.Title;
+
+ if (string.Equals(country, "us", StringComparison.OrdinalIgnoreCase))
+ {
+ item.OfficialRating = result.Rated;
+ }
+ }
+
+ int year;
+
+ if (!string.IsNullOrEmpty(result.Year)
+ && int.TryParse(result.Year, NumberStyles.Number, _usCulture, out year)
+ && year >= 0)
+ {
+ item.ProductionYear = year;
+ }
+
+ var hasCriticRating = item as IHasCriticRating;
+ if (hasCriticRating != null)
+ {
+ // Seeing some bogus RT data on omdb for series, so filter it out here
+ // RT doesn't even have tv series
+ int tomatoMeter;
+
+ if (!string.IsNullOrEmpty(result.tomatoMeter)
+ && int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
+ && tomatoMeter >= 0)
+ {
+ hasCriticRating.CriticRating = tomatoMeter;
+ }
+
+ if (!string.IsNullOrEmpty(result.tomatoConsensus)
+ && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
+ {
+ hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
+ }
+ }
+
+ int voteCount;
+
+ if (!string.IsNullOrEmpty(result.imdbVotes)
+ && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out voteCount)
+ && voteCount >= 0)
+ {
+ item.VoteCount = voteCount;
+ }
+
+ float imdbRating;
+
+ if (!string.IsNullOrEmpty(result.imdbRating)
+ && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out imdbRating)
+ && imdbRating >= 0)
+ {
+ item.CommunityRating = imdbRating;
+ }
+
+ if (!string.IsNullOrEmpty(result.Website))
+ {
+ item.HomePageUrl = result.Website;
+ }
+
+ if (!string.IsNullOrWhiteSpace(result.imdbID))
+ {
+ item.SetProviderId(MetadataProviders.Imdb, result.imdbID);
+ }
+
+ ParseAdditionalMetadata(item, result);
+
+ return true;
+ }
+
internal async Task<RootObject> GetRootObject(string imdbId, CancellationToken cancellationToken)
{
var path = await EnsureItemInfo(imdbId, cancellationToken);
@@ -133,6 +234,40 @@ namespace MediaBrowser.Providers.Omdb
return result;
}
+ internal async Task<SeasonRootObject> GetSeasonRootObject(string imdbId, int seasonId, CancellationToken cancellationToken)
+ {
+ var path = await EnsureSeasonInfo(imdbId, seasonId, cancellationToken);
+
+ string resultString;
+
+ using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 131072))
+ {
+ using (var reader = new StreamReader(stream, new UTF8Encoding(false)))
+ {
+ resultString = reader.ReadToEnd();
+ resultString = resultString.Replace("\"N/A\"", "\"\"");
+ }
+ }
+
+ var result = _jsonSerializer.DeserializeFromString<SeasonRootObject>(resultString);
+ return result;
+ }
+
+ internal static bool IsValidSeries(Dictionary<string, string> seriesProviderIds)
+ {
+ string id;
+ if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id) && !string.IsNullOrEmpty(id))
+ {
+ // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet.
+ if (!string.IsNullOrWhiteSpace(id))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private async Task<string> EnsureItemInfo(string imdbId, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(imdbId))
@@ -173,6 +308,46 @@ namespace MediaBrowser.Providers.Omdb
return path;
}
+ private async Task<string> EnsureSeasonInfo(string seriesImdbId, int seasonId, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrWhiteSpace(seriesImdbId))
+ {
+ throw new ArgumentNullException("imdbId");
+ }
+
+ var imdbParam = seriesImdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? seriesImdbId : "tt" + seriesImdbId;
+
+ var path = GetSeasonFilePath(imdbParam, seasonId);
+
+ var fileInfo = _fileSystem.GetFileSystemInfo(path);
+
+ if (fileInfo.Exists)
+ {
+ // If it's recent or automatic updates are enabled, don't re-download
+ if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 3)
+ {
+ return path;
+ }
+ }
+
+ var url = string.Format("https://www.omdbapi.com/?i={0}&season={1}&detail=full", imdbParam, seasonId);
+
+ using (var stream = await _httpClient.Get(new HttpRequestOptions
+ {
+ Url = url,
+ ResourcePool = ResourcePool,
+ CancellationToken = cancellationToken
+
+ }).ConfigureAwait(false))
+ {
+ var rootObject = _jsonSerializer.DeserializeFromStream<SeasonRootObject>(stream);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ _jsonSerializer.SerializeToFile(rootObject, path);
+ }
+
+ return path;
+ }
+
internal string GetDataFilePath(string imdbId)
{
if (string.IsNullOrEmpty(imdbId))
@@ -187,6 +362,20 @@ namespace MediaBrowser.Providers.Omdb
return Path.Combine(dataPath, filename);
}
+ internal string GetSeasonFilePath(string imdbId, int seasonId)
+ {
+ if (string.IsNullOrEmpty(imdbId))
+ {
+ throw new ArgumentNullException("imdbId");
+ }
+
+ var dataPath = Path.Combine(_configurationManager.ApplicationPaths.CachePath, "omdb");
+
+ var filename = string.Format("{0}_season_{1}.json", imdbId, seasonId);
+
+ return Path.Combine(dataPath, filename);
+ }
+
private void ParseAdditionalMetadata(BaseItem item, RootObject result)
{
// Grab series genres because imdb data is better than tvdb. Leave movies alone
@@ -238,12 +427,23 @@ namespace MediaBrowser.Providers.Omdb
return string.Equals(lang, "en", StringComparison.OrdinalIgnoreCase);
}
+ internal class SeasonRootObject
+ {
+ public string Title { get; set; }
+ public string seriesID { get; set; }
+ public int Season { get; set; }
+ public int? totalSeasons { get; set; }
+ public RootObject[] Episodes { get; set; }
+ public string Response { get; set; }
+ }
+
internal class RootObject
{
public string Title { get; set; }
public string Year { get; set; }
public string Rated { get; set; }
public string Released { get; set; }
+ public int Episode { get; set; }
public string Runtime { get; set; }
public string Genre { get; set; }
public string Director { get; set; }
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 2a3150c78..4e2d9a8d2 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -428,7 +428,8 @@ namespace MediaBrowser.Providers.TV
Name = name,
IndexNumber = episodeNumber,
ParentIndexNumber = seasonNumber,
- Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode))
+ Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode)),
+ IsVirtualItem = true
};
episode.SetParent(season);
diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
index ebbefbeb1..21668f014 100644
--- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.TV
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{
- var result = new MetadataResult<Episode>
+ var result = new MetadataResult<Episode>()
{
Item = new Episode()
};
@@ -53,30 +53,16 @@ namespace MediaBrowser.Providers.TV
return result;
}
- var imdbId = info.GetProviderId(MetadataProviders.Imdb);
- if (string.IsNullOrWhiteSpace(imdbId))
+ if (OmdbProvider.IsValidSeries(info.SeriesProviderIds) && info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue)
{
- imdbId = await GetEpisodeImdbId(info, cancellationToken).ConfigureAwait(false);
- }
-
- if (!string.IsNullOrEmpty(imdbId))
- {
- result.Item.SetProviderId(MetadataProviders.Imdb, imdbId);
- result.HasMetadata = true;
+ var seriesImdbId = info.SeriesProviderIds[MetadataProviders.Imdb.ToString()];
- await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+ result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _configurationManager).FetchEpisodeData(result.Item, info.IndexNumber.Value, info.ParentIndexNumber.Value, seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
}
return result;
}
- private async Task<string> GetEpisodeImdbId(EpisodeInfo info, CancellationToken cancellationToken)
- {
- var results = await GetSearchResults(info, cancellationToken).ConfigureAwait(false);
- var first = results.FirstOrDefault();
- return first == null ? null : first.GetProviderId(MetadataProviders.Imdb);
- }
-
public int Order
{
get
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index 041969a59..f440baf5b 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -76,11 +76,6 @@ namespace MediaBrowser.Providers.TV
{
targetItem.AirDays = sourceItem.AirDays;
}
-
- if (mergeMetadataSettings)
- {
- targetItem.DisplaySpecialsWithSeasons = sourceItem.DisplaySpecialsWithSeasons;
- }
}
}
}
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index 3c0a5fc73..d044c828f 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -195,28 +195,35 @@ namespace MediaBrowser.Providers.TV
private async void LibraryUpdateTimerCallback(object state)
{
- if (MissingEpisodeProvider.IsRunning)
+ try
{
- return;
- }
+ if (MissingEpisodeProvider.IsRunning)
+ {
+ return;
+ }
- if (_libraryManager.IsScanRunning)
- {
- return ;
- }
+ if (_libraryManager.IsScanRunning)
+ {
+ return;
+ }
- var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
- {
- IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true,
- GroupByPresentationUniqueKey = false
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
- }).Cast<Series>().ToList();
+ }).Cast<Series>().ToList();
- var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
+ var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
- await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
- .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false);
+ await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
+ .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in SeriesPostScanTask", ex);
+ }
}
private bool FilterItem(BaseItem item)
diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
index b0e05a5bc..c992def39 100644
--- a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
+++ b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
@@ -15,54 +15,26 @@ namespace MediaBrowser.Server.Implementations.Activity
{
public class ActivityRepository : BaseSqliteRepository, IActivityRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveActivityCommand;
-
- public ActivityRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public ActivityRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "activitylog.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists ActivityLogEntries (Id GUID PRIMARY KEY, Name TEXT, Overview TEXT, ShortOverview TEXT, Type TEXT, ItemId TEXT, UserId TEXT, DateCreated DATETIME, LogSeverity TEXT)",
- "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveActivityCommand = _connection.CreateCommand();
- _saveActivityCommand.CommandText = "replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)";
-
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Id");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Name");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Overview");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ShortOverview");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Type");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ItemId");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@UserId");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@DateCreated");
- _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@LogSeverity");
+ connection.RunQueries(queries, Logger);
+ }
}
private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries";
@@ -79,128 +51,145 @@ namespace MediaBrowser.Server.Implementations.Activity
throw new ArgumentNullException("entry");
}
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var saveActivityCommand = connection.CreateCommand())
+ {
+ saveActivityCommand.CommandText = "replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)";
- IDbTransaction transaction = null;
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Id");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Name");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Overview");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@ShortOverview");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@Type");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@ItemId");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@UserId");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@DateCreated");
+ saveActivityCommand.Parameters.Add(saveActivityCommand, "@LogSeverity");
- try
- {
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- var index = 0;
+ try
+ {
+ transaction = connection.BeginTransaction();
- _saveActivityCommand.GetParameter(index++).Value = new Guid(entry.Id);
- _saveActivityCommand.GetParameter(index++).Value = entry.Name;
- _saveActivityCommand.GetParameter(index++).Value = entry.Overview;
- _saveActivityCommand.GetParameter(index++).Value = entry.ShortOverview;
- _saveActivityCommand.GetParameter(index++).Value = entry.Type;
- _saveActivityCommand.GetParameter(index++).Value = entry.ItemId;
- _saveActivityCommand.GetParameter(index++).Value = entry.UserId;
- _saveActivityCommand.GetParameter(index++).Value = entry.Date;
- _saveActivityCommand.GetParameter(index++).Value = entry.Severity.ToString();
+ var index = 0;
- _saveActivityCommand.Transaction = transaction;
+ saveActivityCommand.GetParameter(index++).Value = new Guid(entry.Id);
+ saveActivityCommand.GetParameter(index++).Value = entry.Name;
+ saveActivityCommand.GetParameter(index++).Value = entry.Overview;
+ saveActivityCommand.GetParameter(index++).Value = entry.ShortOverview;
+ saveActivityCommand.GetParameter(index++).Value = entry.Type;
+ saveActivityCommand.GetParameter(index++).Value = entry.ItemId;
+ saveActivityCommand.GetParameter(index++).Value = entry.UserId;
+ saveActivityCommand.GetParameter(index++).Value = entry.Date;
+ saveActivityCommand.GetParameter(index++).Value = entry.Severity.ToString();
- _saveActivityCommand.ExecuteNonQuery();
+ saveActivityCommand.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ saveActivityCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit)
{
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseActivitySelectText;
-
- var whereClauses = new List<string>();
-
- if (minDate.HasValue)
+ using (var cmd = connection.CreateCommand())
{
- whereClauses.Add("DateCreated>=@DateCreated");
- cmd.Parameters.Add(cmd, "@DateCreated", DbType.Date).Value = minDate.Value;
- }
+ cmd.CommandText = BaseActivitySelectText;
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereClauses = new List<string>();
- if (startIndex.HasValue && startIndex.Value > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
+ if (minDate.HasValue)
+ {
+ whereClauses.Add("DateCreated>=@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateCreated", DbType.Date).Value = minDate.Value;
+ }
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
-
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
- pagingWhereText,
- startIndex.Value.ToString(_usCulture)));
- }
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
-
- cmd.CommandText += whereText;
+ if (startIndex.HasValue && startIndex.Value > 0)
+ {
+ var pagingWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += " ORDER BY DateCreated DESC";
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
+ pagingWhereText,
+ startIndex.Value.ToString(_usCulture)));
+ }
- if (limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + limit.Value.ToString(_usCulture);
- }
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += "; select count (Id) from ActivityLogEntries" + whereTextWithoutPaging;
+ cmd.CommandText += whereText;
- var list = new List<ActivityLogEntry>();
- var count = 0;
+ cmd.CommandText += " ORDER BY DateCreated DESC";
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ if (limit.HasValue)
{
- list.Add(GetEntry(reader));
+ cmd.CommandText += " LIMIT " + limit.Value.ToString(_usCulture);
}
- if (reader.NextResult() && reader.Read())
+ cmd.CommandText += "; select count (Id) from ActivityLogEntries" + whereTextWithoutPaging;
+
+ var list = new List<ActivityLogEntry>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- count = reader.GetInt32(0);
+ while (reader.Read())
+ {
+ list.Add(GetEntry(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- }
- return new QueryResult<ActivityLogEntry>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
+ return new QueryResult<ActivityLogEntry>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
}
}
@@ -260,19 +249,5 @@ namespace MediaBrowser.Server.Implementations.Activity
return info;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index 6a9842cb2..609c24692 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -191,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var dtoOptions = new DtoOptions();
- var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+ var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -596,7 +596,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var dtoOptions = new DtoOptions();
- var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user)
+ var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -863,7 +863,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var dtoOptions = new DtoOptions();
- var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+ var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -1012,7 +1012,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var dtoOptions = new DtoOptions();
- var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
+ var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
.ToArray();
var result = new QueryResult<BaseItemDto>
@@ -1172,8 +1172,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
items = ApplyFilters(items, query.Filters, user);
- var sortBy = query.SortBy.Length == 0 ? new[] { ItemSortBy.SortName } : query.SortBy;
- items = _libraryManager.Sort(items, user, sortBy, query.SortOrder ?? SortOrder.Ascending);
+ items = _libraryManager.Sort(items, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending);
var all = items.ToList();
var totalCount = totalCountFromProvider ?? all.Count;
@@ -1250,10 +1249,22 @@ namespace MediaBrowser.Server.Implementations.Channels
{
item = GetItemById<MusicAlbum>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
}
+ else if (info.FolderType == ChannelFolderType.MusicArtist)
+ {
+ item = GetItemById<MusicArtist>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+ }
else if (info.FolderType == ChannelFolderType.PhotoAlbum)
{
item = GetItemById<PhotoAlbum>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
}
+ else if (info.FolderType == ChannelFolderType.Series)
+ {
+ item = GetItemById<Series>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+ }
+ else if (info.FolderType == ChannelFolderType.Season)
+ {
+ item = GetItemById<Season>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+ }
else
{
item = GetItemById<Folder>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
@@ -1307,6 +1318,19 @@ namespace MediaBrowser.Server.Implementations.Channels
item.OfficialRating = info.OfficialRating;
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
item.Tags = info.Tags;
+ item.HomePageUrl = info.HomePageUrl;
+ }
+
+ var hasArtists = item as IHasArtist;
+ if (hasArtists != null)
+ {
+ hasArtists.Artists = info.Artists;
+ }
+
+ var hasAlbumArtists = item as IHasAlbumArtist;
+ if (hasAlbumArtists != null)
+ {
+ hasAlbumArtists.AlbumArtists = info.AlbumArtists;
}
var trailer = item as Trailer;
diff --git a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
index 561d46229..3e33066ae 100644
--- a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Server.Implementations.Collections
public bool IsHiddenFromUser(User user)
{
- return !user.Configuration.DisplayCollectionsView;
+ return !ConfigurationManager.Configuration.DisplayCollectionsView;
}
public override string CollectionType
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index f3d545492..6190a9da0 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -177,7 +177,7 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- var localAddress = _appHost.LocalApiUrl;
+ var localAddress = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
!string.IsNullOrWhiteSpace(ConnectAccessKey);
@@ -217,24 +217,26 @@ namespace MediaBrowser.Server.Implementations.Connect
}
private string _lastReportedIdentifier;
- private string GetConnectReportingIdentifier()
+ private async Task<string> GetConnectReportingIdentifier()
{
- return GetConnectReportingIdentifier(_appHost.LocalApiUrl, WanApiAddress);
+ var url = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
+ return GetConnectReportingIdentifier(url, WanApiAddress);
}
private string GetConnectReportingIdentifier(string localAddress, string remoteAddress)
{
return (remoteAddress ?? string.Empty) + (localAddress ?? string.Empty);
}
- void _config_ConfigurationUpdated(object sender, EventArgs e)
+ async void _config_ConfigurationUpdated(object sender, EventArgs e)
{
// If info hasn't changed, don't report anything
- if (string.Equals(_lastReportedIdentifier, GetConnectReportingIdentifier(), StringComparison.OrdinalIgnoreCase))
+ var connectIdentifier = await GetConnectReportingIdentifier().ConfigureAwait(false);
+ if (string.Equals(_lastReportedIdentifier, connectIdentifier, StringComparison.OrdinalIgnoreCase))
{
return;
}
- UpdateConnectInfo();
+ await UpdateConnectInfo().ConfigureAwait(false);
}
private async Task CreateServerRegistration(string wanApiAddress, string localAddress)
diff --git a/MediaBrowser.Server.Implementations/Connect/Responses.cs b/MediaBrowser.Server.Implementations/Connect/Responses.cs
index e7c3f8154..f86527829 100644
--- a/MediaBrowser.Server.Implementations/Connect/Responses.cs
+++ b/MediaBrowser.Server.Implementations/Connect/Responses.cs
@@ -60,7 +60,6 @@ namespace MediaBrowser.Server.Implementations.Connect
{
return new ConnectUserPreferences
{
- GroupMoviesIntoBoxSets = config.GroupMoviesIntoBoxSets,
PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
SubtitleMode = config.SubtitleMode,
PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 5588405e3..f21dd27ff 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -86,7 +86,7 @@ namespace MediaBrowser.Server.Implementations.Dto
return GetBaseItemDto(item, options, user, owner);
}
- public IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
+ public async Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
{
var syncJobItems = GetSyncedItemProgress(options);
var syncDictionary = GetSyncedItemProgressDictionary(syncJobItems);
@@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.Dto
foreach (var item in items)
{
- var dto = GetBaseItemDtoInternal(item, options, syncDictionary, user, owner);
+ var dto = await GetBaseItemDtoInternal(item, options, syncDictionary, user, owner).ConfigureAwait(false);
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
@@ -131,8 +131,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (programTuples.Count > 0)
{
- var task = _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user);
- Task.WaitAll(task);
+ await _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).ConfigureAwait(false);
}
if (channelTuples.Count > 0)
@@ -159,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
var syncProgress = GetSyncedItemProgress(options);
- var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user, owner);
+ var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user, owner).Result;
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
{
@@ -300,7 +299,7 @@ namespace MediaBrowser.Server.Implementations.Dto
}
}
- private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary<string, SyncedItemProgress> syncProgress, User user = null, BaseItem owner = null)
+ private async Task<BaseItemDto> GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary<string, SyncedItemProgress> syncProgress, User user = null, BaseItem owner = null)
{
var fields = options.Fields;
@@ -349,7 +348,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (user != null)
{
- AttachUserSpecificInfo(dto, item, user, fields, syncProgress);
+ await AttachUserSpecificInfo(dto, item, user, fields, syncProgress).ConfigureAwait(false);
}
var hasMediaSources = item as IHasMediaSources;
@@ -416,9 +415,9 @@ namespace MediaBrowser.Server.Implementations.Dto
{
var syncProgress = GetSyncedItemProgress(options);
- var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user);
+ var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user).Result;
- if (options.Fields.Contains(ItemFields.ItemCounts))
+ if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts))
{
SetItemByNameInfo(item, dto, taggedItems, user);
}
@@ -465,26 +464,31 @@ namespace MediaBrowser.Server.Implementations.Dto
/// <param name="user">The user.</param>
/// <param name="fields">The fields.</param>
/// <param name="syncProgress">The synchronize progress.</param>
- private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields, Dictionary<string, SyncedItemProgress> syncProgress)
+ private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields, Dictionary<string, SyncedItemProgress> syncProgress)
{
if (item.IsFolder)
{
- var userData = _userDataRepository.GetUserData(user, item);
+ var folder = (Folder)item;
- // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice
- // TODO: Improve in future
- dto.UserData = GetUserItemDataDto(userData);
+ if (item.SourceType == SourceType.Library && folder.SupportsUserDataFromChildren && fields.Contains(ItemFields.SyncInfo))
+ {
+ // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice
+ // TODO: Improve in future
+ dto.UserData = GetUserItemDataDto(_userDataRepository.GetUserData(user, item));
- var folder = (Folder)item;
+ await SetSpecialCounts(folder, user, dto, fields, syncProgress).ConfigureAwait(false);
+
+ dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue &&
+ dto.UserData.PlayedPercentage.Value >= 100;
+ }
+ else
+ {
+ dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false);
+ }
if (item.SourceType == SourceType.Library)
{
dto.ChildCount = GetChildCount(folder, user);
-
- if (folder.SupportsUserDataFromChildren)
- {
- SetSpecialCounts(folder, user, dto, fields, syncProgress);
- }
}
if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
@@ -496,13 +500,11 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.DateLastMediaAdded = folder.DateLastMediaAdded;
}
-
- dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100;
}
else
{
- dto.UserData = _userDataRepository.GetUserDataDto(item, user);
+ dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result;
}
dto.PlayAccess = item.GetPlayAccess(user);
@@ -517,7 +519,7 @@ namespace MediaBrowser.Server.Implementations.Dto
if (season != null)
{
- dto.SeasonUserData = _userDataRepository.GetUserDataDto(season, user);
+ dto.SeasonUserData = await _userDataRepository.GetUserDataDto(season, user).ConfigureAwait(false);
}
}
}
@@ -537,8 +539,14 @@ namespace MediaBrowser.Server.Implementations.Dto
private int GetChildCount(Folder folder, User user)
{
- return folder.GetChildren(user, true)
- .Count();
+ // Right now this is too slow to calculate for top level folders on a per-user basis
+ // Just return something so that apps that are expecting a value won't think the folders are empty
+ if (folder is ICollectionFolder || folder is UserView)
+ {
+ return new Random().Next(1, 10);
+ }
+
+ return folder.GetChildCount(user);
}
/// <summary>
@@ -1268,26 +1276,22 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.Artists = hasArtist.Artists;
- dto.ArtistItems = hasArtist
- .Artists
+ var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
+ {
+ EnableTotalRecordCount = false,
+ ItemIds = new[] { item.Id.ToString("N") }
+ });
+
+ dto.ArtistItems = artistItems.Items
.Select(i =>
{
- try
- {
- var artist = _libraryManager.GetArtist(i);
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- }
- catch (Exception ex)
+ var artist = i.Item1;
+ return new NameIdPair
{
- _logger.ErrorException("Error getting artist", ex);
- return null;
- }
+ Name = artist.Name,
+ Id = artist.Id.ToString("N")
+ };
})
- .Where(i => i != null)
.ToList();
}
@@ -1296,26 +1300,22 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
- dto.AlbumArtists = hasAlbumArtist
- .AlbumArtists
+ var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
+ {
+ EnableTotalRecordCount = false,
+ ItemIds = new[] { item.Id.ToString("N") }
+ });
+
+ dto.AlbumArtists = artistItems.Items
.Select(i =>
{
- try
+ var artist = i.Item1;
+ return new NameIdPair
{
- var artist = _libraryManager.GetArtist(i);
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting album artist", ex);
- return null;
- }
+ Name = artist.Name,
+ Id = artist.Id.ToString("N")
+ };
})
- .Where(i => i != null)
.ToList();
}
@@ -1466,11 +1466,6 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AirTime = series.AirTime;
dto.SeriesStatus = series.Status;
- if (fields.Contains(ItemFields.Settings))
- {
- dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
- }
-
dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
}
@@ -1589,26 +1584,25 @@ namespace MediaBrowser.Server.Implementations.Dto
/// <param name="fields">The fields.</param>
/// <param name="syncProgress">The synchronize progress.</param>
/// <returns>Task.</returns>
- private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List<ItemFields> fields, Dictionary<string, SyncedItemProgress> syncProgress)
+ private async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List<ItemFields> fields, Dictionary<string, SyncedItemProgress> syncProgress)
{
var recursiveItemCount = 0;
var unplayed = 0;
double totalPercentPlayed = 0;
double totalSyncPercent = 0;
- var addSyncInfo = fields.Contains(ItemFields.SyncInfo);
- var children = folder.GetItems(new InternalItemsQuery
+ var children = await folder.GetItems(new InternalItemsQuery
{
IsFolder = false,
Recursive = true,
ExcludeLocationTypes = new[] { LocationType.Virtual },
User = user
- }).Result.Items;
+ }).ConfigureAwait(false);
// Loop through each recursive child
- foreach (var child in children)
+ foreach (var child in children.Items)
{
var userdata = _userDataRepository.GetUserData(user, child);
@@ -1638,26 +1632,23 @@ namespace MediaBrowser.Server.Implementations.Dto
unplayed++;
}
- if (addSyncInfo)
+ double percent = 0;
+ SyncedItemProgress syncItemProgress;
+ if (syncProgress.TryGetValue(child.Id.ToString("N"), out syncItemProgress))
{
- double percent = 0;
- SyncedItemProgress syncItemProgress;
- if (syncProgress.TryGetValue(child.Id.ToString("N"), out syncItemProgress))
+ switch (syncItemProgress.Status)
{
- switch (syncItemProgress.Status)
- {
- case SyncJobItemStatus.Synced:
- percent = 100;
- break;
- case SyncJobItemStatus.Converting:
- case SyncJobItemStatus.ReadyToTransfer:
- case SyncJobItemStatus.Transferring:
- percent = 50;
- break;
- }
+ case SyncJobItemStatus.Synced:
+ percent = 100;
+ break;
+ case SyncJobItemStatus.Converting:
+ case SyncJobItemStatus.ReadyToTransfer:
+ case SyncJobItemStatus.Transferring:
+ percent = 50;
+ break;
}
- totalSyncPercent += percent;
}
+ totalSyncPercent += percent;
}
dto.RecursiveItemCount = recursiveItemCount;
@@ -1667,13 +1658,10 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.UserData.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
- if (addSyncInfo)
+ var pct = totalSyncPercent / recursiveItemCount;
+ if (pct > 0)
{
- var pct = totalSyncPercent / recursiveItemCount;
- if (pct > 0)
- {
- dto.SyncPercent = pct;
- }
+ dto.SyncPercent = pct;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
index df6a9e654..d5f265dda 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
@@ -8,6 +8,9 @@ using MediaBrowser.Model.Tasks;
using System;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -18,16 +21,18 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private readonly ITaskManager _iTaskManager;
private readonly ISessionManager _sessionManager;
private readonly IServerConfigurationManager _config;
+ private readonly ILiveTvManager _liveTvManager;
private Timer _timer;
- public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config)
+ public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager)
{
_appHost = appHost;
_logger = logger;
_iTaskManager = iTaskManager;
_sessionManager = sessionManager;
_config = config;
+ _liveTvManager = liveTvManager;
}
public void Run()
@@ -44,34 +49,55 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
if (_appHost.HasPendingRestart)
{
- _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
}
}
- private void TimerCallback(object state)
+ private async void TimerCallback(object state)
{
- if (_config.Configuration.EnableAutomaticRestart && IsIdle())
+ if (_config.Configuration.EnableAutomaticRestart)
{
- DisposeTimer();
+ var isIdle = await IsIdle().ConfigureAwait(false);
- try
- {
- _appHost.Restart();
- }
- catch (Exception ex)
+ if (isIdle)
{
- _logger.ErrorException("Error restarting server", ex);
+ DisposeTimer();
+
+ try
+ {
+ _appHost.Restart();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error restarting server", ex);
+ }
}
}
}
- private bool IsIdle()
+ private async Task<bool> IsIdle()
{
if (_iTaskManager.ScheduledTasks.Any(i => i.State != TaskState.Idle))
{
return false;
}
+ if (_liveTvManager.Services.Count == 1)
+ {
+ try
+ {
+ var timers = await _liveTvManager.GetTimers(new TimerQuery(), CancellationToken.None).ConfigureAwait(false);
+ if (timers.Items.Any(i => i.Status == RecordingStatus.InProgress))
+ {
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting timers", ex);
+ }
+ }
+
var now = DateTime.UtcNow;
return !_sessionManager.Sessions.Any(i => (now - i.LastActivityDate).TotalMinutes < 30);
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 5777a0af7..50ad3cfbc 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -93,7 +93,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery();
- _timer = new PeriodicTimer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
+ _timer = new PeriodicTimer(ClearCreatedRules, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
_ssdp.MessageReceived += _ssdp_MessageReceived;
@@ -102,12 +102,43 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
_isStarted = true;
}
+ private void ClearCreatedRules(object state)
+ {
+ _createdRules = new List<string>();
+ _usnsHandled = new List<string>();
+ }
+
void _ssdp_MessageReceived(object sender, SsdpMessageEventArgs e)
{
var endpoint = e.EndPoint as IPEndPoint;
- if (endpoint != null && e.LocalEndPoint != null)
+ if (endpoint == null || e.LocalEndPoint == null)
{
+ return;
+ }
+
+ string usn;
+ if (!e.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
+
+ string nt;
+ if (!e.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
+
+ // Filter device type
+ if (usn.IndexOf("WANIPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ nt.IndexOf("WANIPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ usn.IndexOf("WANPPPConnection:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ nt.IndexOf("WANPPPConnection:", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ return;
+ }
+
+ var identifier = string.IsNullOrWhiteSpace(usn) ? nt : usn;
+
+ if (!_usnsHandled.Contains(identifier))
+ {
+ _usnsHandled.Add(identifier);
+
+ _logger.Debug("Calling Nat.Handle on " + identifier);
NatUtility.Handle(e.LocalEndPoint.Address, e.Message, endpoint, NatProtocol.Upnp);
}
}
@@ -151,6 +182,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
}
private List<string> _createdRules = new List<string>();
+ private List<string> _usnsHandled = new List<string>();
private void CreateRules(INatDevice device)
{
// On some systems the device discovered event seems to fire repeatedly
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs
new file mode 100644
index 000000000..cc4ef1972
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+ public class RecordingNotifier : IServerEntryPoint
+ {
+ private readonly ILiveTvManager _liveTvManager;
+ private readonly ISessionManager _sessionManager;
+ private readonly IUserManager _userManager;
+ private readonly ILogger _logger;
+
+ public RecordingNotifier(ISessionManager sessionManager, IUserManager userManager, ILogger logger, ILiveTvManager liveTvManager)
+ {
+ _sessionManager = sessionManager;
+ _userManager = userManager;
+ _logger = logger;
+ _liveTvManager = liveTvManager;
+ }
+
+ public void Run()
+ {
+ _liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
+ _liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
+ _liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
+ _liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+ }
+
+ private void _liveTvManager_SeriesTimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("SeriesTimerCreated", e.Argument);
+ }
+
+ private void _liveTvManager_TimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("TimerCreated", e.Argument);
+ }
+
+ private void _liveTvManager_SeriesTimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("SeriesTimerCancelled", e.Argument);
+ }
+
+ private void _liveTvManager_TimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+ {
+ SendMessage("TimerCancelled", e.Argument);
+ }
+
+ private async void SendMessage(string name, TimerEventInfo info)
+ {
+ var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).ToList();
+
+ foreach (var user in users)
+ {
+ try
+ {
+ await _sessionManager.SendMessageToUserSessions<TimerEventInfo>(user.Id.ToString("N"), name, info, CancellationToken.None);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error sending message", ex);
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ _liveTvManager.TimerCancelled -= _liveTvManager_TimerCancelled;
+ _liveTvManager.SeriesTimerCancelled -= _liveTvManager_SeriesTimerCancelled;
+ _liveTvManager.TimerCreated -= _liveTvManager_TimerCreated;
+ _liveTvManager.SeriesTimerCreated -= _liveTvManager_SeriesTimerCreated;
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index b059e4144..b616b7761 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -119,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
.DistinctBy(i => i.Id)
.Select(i =>
{
- var dto = _userDataManager.GetUserDataDto(i, user);
+ var dto = _userDataManager.GetUserDataDto(i, user).Result;
dto.ItemId = i.Id.ToString("N");
return dto;
})
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index 6cedaa6a9..1d4829260 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -294,7 +294,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return null;
}
- public object GetStaticFileResult(IRequest requestContext,
+ public Task<object> GetStaticFileResult(IRequest requestContext,
string path,
FileShare fileShare = FileShare.Read)
{
@@ -310,7 +310,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
});
}
- public object GetStaticFileResult(IRequest requestContext,
+ public Task<object> GetStaticFileResult(IRequest requestContext,
StaticFileResultOptions options)
{
var path = options.Path;
@@ -351,7 +351,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare);
}
- public object GetStaticResult(IRequest requestContext,
+ public Task<object> GetStaticResult(IRequest requestContext,
Guid cacheKey,
DateTime? lastDateModified,
TimeSpan? cacheDuration,
@@ -372,7 +372,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
});
}
- public object GetStaticResult(IRequest requestContext, StaticResultOptions options)
+ public async Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options)
{
var cacheKey = options.CacheKey;
options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -398,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
var compress = ShouldCompressResponse(requestContext, contentType);
- var hasOptions = GetStaticResult(requestContext, options, compress).Result;
+ var hasOptions = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false);
AddResponseHeaders(hasOptions, options.ResponseHeaders);
return hasOptions;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
index ce8100025..bfbb228ed 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
{
var durationMs = duration.TotalMilliseconds;
- var logSuffix = durationMs >= 1000 ? "ms (slow)" : "ms";
+ var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 020856886..fb4397462 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -39,6 +39,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+ public Func<IDisposable> ResultScope { get; set; }
+ public List<Cookie> Cookies { get; private set; }
+
/// <summary>
/// Additional HTTP Headers
/// </summary>
@@ -81,6 +84,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
Options["Accept-Ranges"] = "bytes";
StatusCode = HttpStatusCode.PartialContent;
+ Cookies = new List<Cookie>();
SetRangeValues();
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 357f5c976..bc3e7b163 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -104,6 +104,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
info.DeviceId = tokenInfo.DeviceId;
}
+ if (string.IsNullOrWhiteSpace(info.Version))
+ {
+ info.Version = tokenInfo.AppVersion;
+ }
}
else
{
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
index ed9e17b6b..efa850922 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Text;
using System.Web;
+using ServiceStack;
using ServiceStack.Web;
namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
@@ -116,6 +117,21 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
}
+ public string Accept
+ {
+ get
+ {
+ return string.IsNullOrEmpty(request.Headers[HttpHeaders.Accept]) ? null : request.Headers[HttpHeaders.Accept];
+ }
+ }
+
+ public string Authorization
+ {
+ get
+ {
+ return string.IsNullOrEmpty(request.Headers[HttpHeaders.Authorization]) ? null : request.Headers[HttpHeaders.Authorization];
+ }
+ }
protected bool validate_cookies, validate_query_string, validate_form;
protected bool checked_cookies, checked_query_string, checked_form;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
index 30849d441..c7d889505 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
this.OperationName = operationName;
this.RequestAttributes = requestAttributes;
this.request = httpContext.Request;
- this.response = new WebSocketSharpResponse(logger, httpContext.Response);
+ this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
this.RequestPreferences = new RequestPreferences(this);
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index 171dacb22..e08be8bd1 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Net;
using MediaBrowser.Model.Logging;
@@ -14,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
private readonly ILogger _logger;
private readonly HttpListenerResponse response;
- public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response)
+ public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
{
_logger = logger;
this.response = response;
+ Items = new Dictionary<string, object>();
+ Request = request;
}
+ public IRequest Request { get; private set; }
public bool UseBufferedStream { get; set; }
-
+ public Dictionary<string, object> Items { get; private set; }
public object OriginalResponse
{
get { return response; }
@@ -58,6 +62,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
response.AddHeader(name, value);
}
+ public string GetHeader(string name)
+ {
+ return response.Headers[name];
+ }
+
public void Redirect(string url)
{
response.Redirect(url);
@@ -142,5 +151,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
public bool KeepAlive { get; set; }
+
+ public void ClearCookies()
+ {
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs b/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs
index aeaac80e8..d91f316d6 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var requestedFile = Path.Combine(swaggerDirectory, request.ResourceName.Replace('/', Path.DirectorySeparatorChar));
- return ResultFactory.GetStaticFileResult(Request, requestedFile);
+ return ResultFactory.GetStaticFileResult(Request, requestedFile).Result;
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
index 18c52ab29..4bea6ad34 100644
--- a/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
+++ b/MediaBrowser.Server.Implementations/IO/FileRefresher.cs
@@ -93,8 +93,15 @@ namespace MediaBrowser.Server.Implementations.IO
private async void OnTimerCallback(object state)
{
+ List<string> paths;
+
+ lock (_timerLock)
+ {
+ paths = _affectedPaths.ToList();
+ }
+
// Extend the timer as long as any of the paths are still being written to.
- if (_affectedPaths.Any(IsFileLocked))
+ if (paths.Any(IsFileLocked))
{
Logger.Info("Timer extended.");
RestartTimer();
@@ -108,7 +115,7 @@ namespace MediaBrowser.Server.Implementations.IO
try
{
- await ProcessPathChanges(_affectedPaths.ToList()).ConfigureAwait(false);
+ await ProcessPathChanges(paths.ToList()).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 032f8dbb7..883864156 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -33,6 +33,7 @@ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Net;
@@ -362,6 +363,10 @@ namespace MediaBrowser.Server.Implementations.Library
return;
}
}
+ if (item is Photo)
+ {
+ return;
+ }
//if (!(item is Folder))
//{
// return;
@@ -939,9 +944,7 @@ namespace MediaBrowser.Server.Implementations.Library
private T CreateItemByName<T>(string path, string name)
where T : BaseItem, new()
{
- var isArtist = typeof(T) == typeof(MusicArtist);
-
- if (isArtist)
+ if (typeof(T) == typeof(MusicArtist))
{
var existing = GetItemList(new InternalItemsQuery
{
@@ -1272,50 +1275,135 @@ namespace MediaBrowser.Server.Implementations.Library
return item;
}
- public BaseItem GetMemoryItemById(Guid id)
+ public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
{
- if (id == Guid.Empty)
+ if (query.User != null)
{
- throw new ArgumentNullException("id");
+ AddUserToQuery(query, query.User);
}
- BaseItem item;
+ return ItemRepository.GetItemList(query);
+ }
- LibraryItemsCache.TryGetValue(id, out item);
+ public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
+ {
+ if (query.User != null)
+ {
+ AddUserToQuery(query, query.User);
+ }
- return item;
+ if (query.EnableTotalRecordCount)
+ {
+ return ItemRepository.GetItems(query);
+ }
+
+ return new QueryResult<BaseItem>
+ {
+ Items = ItemRepository.GetItemList(query).ToArray()
+ };
}
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
+ public List<Guid> GetItemIds(InternalItemsQuery query)
{
if (query.User != null)
{
AddUserToQuery(query, query.User);
}
- var result = ItemRepository.GetItemIdsList(query);
+ return ItemRepository.GetItemIdsList(query);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
+ {
+ if (query.User != null)
+ {
+ AddUserToQuery(query, query.User);
+ }
- return result.Select(GetItemById).Where(i => i != null);
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetStudios(query);
}
- public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
{
if (query.User != null)
{
AddUserToQuery(query, query.User);
}
- return ItemRepository.GetItems(query);
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetGenres(query);
}
- public List<Guid> GetItemIds(InternalItemsQuery query)
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
{
if (query.User != null)
{
AddUserToQuery(query, query.User);
}
- return ItemRepository.GetItemIdsList(query);
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetGameGenres(query);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
+ {
+ if (query.User != null)
+ {
+ AddUserToQuery(query, query.User);
+ }
+
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetMusicGenres(query);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
+ {
+ if (query.User != null)
+ {
+ AddUserToQuery(query, query.User);
+ }
+
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetArtists(query);
+ }
+
+ private void SetTopParentOrAncestorIds(InternalItemsQuery query)
+ {
+ if (query.AncestorIds.Length == 0)
+ {
+ return;
+ }
+
+ var parents = query.AncestorIds.Select(i => GetItemById(new Guid(i))).ToList();
+
+ if (parents.All(i =>
+ {
+ if (i is ICollectionFolder || i is UserView)
+ {
+ return true;
+ }
+
+ //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
+ return false;
+
+ }))
+ {
+ // Optimize by querying against top level views
+ query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
+ query.AncestorIds = new string[] { };
+ }
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
+ {
+ if (query.User != null)
+ {
+ AddUserToQuery(query, query.User);
+ }
+
+ SetTopParentOrAncestorIds(query);
+ return ItemRepository.GetAlbumArtists(query);
}
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds)
@@ -1324,7 +1412,7 @@ namespace MediaBrowser.Server.Implementations.Library
SetTopParentIdsOrAncestors(query, parents);
- return GetItemIds(query).Select(GetItemById).Where(i => i != null);
+ return ItemRepository.GetItemList(query);
}
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
@@ -1346,18 +1434,12 @@ namespace MediaBrowser.Server.Implementations.Library
if (query.EnableTotalRecordCount)
{
- var initialResult = ItemRepository.GetItemIds(query);
-
- return new QueryResult<BaseItem>
- {
- TotalRecordCount = initialResult.TotalRecordCount,
- Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray()
- };
+ return ItemRepository.GetItems(query);
}
return new QueryResult<BaseItem>
{
- Items = ItemRepository.GetItemIdsList(query).Select(GetItemById).Where(i => i != null).ToArray()
+ Items = ItemRepository.GetItemList(query).ToArray()
};
}
@@ -1379,7 +1461,7 @@ namespace MediaBrowser.Server.Implementations.Library
return true;
}
- _logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
+ //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
return false;
}))
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 0ef7efe1b..1bcb02ac3 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -73,6 +73,10 @@ namespace MediaBrowser.Server.Implementations.Library
{
return false;
}
+ if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
return true;
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 9edd3f83f..703a33856 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -126,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
}
else
{
- var videoInfo = parser.ResolveFile(args.Path);
+ var videoInfo = parser.Resolve(args.Path, false, false);
if (videoInfo == null)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index c2606dc4b..715f3c522 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -202,13 +202,21 @@ namespace MediaBrowser.Server.Implementations.Library
return GetUserData(userId, item.Id, item.GetUserDataKeys());
}
- public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
+ public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user)
{
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- item.FillUserDataDtoValues(dto, userData, user);
+ await item.FillUserDataDtoValues(dto, userData, null, user).ConfigureAwait(false);
+ return dto;
+ }
+
+ public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user)
+ {
+ var userData = GetUserData(user.Id, item);
+ var dto = GetUserItemDataDto(userData);
+ await item.FillUserDataDtoValues(dto, userData, itemDto, user).ConfigureAwait(false);
return dto;
}
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 5ba83d6c7..6456d7f81 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -729,7 +729,7 @@ namespace MediaBrowser.Server.Implementations.Library
var text = new StringBuilder();
- var localAddress = _appHost.LocalApiUrl ?? string.Empty;
+ var localAddress = _appHost.GetLocalApiUrl().Result ?? string.Empty;
text.AppendLine("Use your web browser to visit:");
text.AppendLine(string.Empty);
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index e6a571f07..319e715c3 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -202,23 +202,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var user = _userManager.GetUserById(request.UserId);
- var includeTypes = request.IncludeItemTypes;
-
- var currentUser = user;
-
- var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i =>
- {
- if (request.IsPlayed.HasValue)
- {
- var val = request.IsPlayed.Value;
- if (i is Video && i.IsPlayed(currentUser) != val)
- {
- return false;
- }
- }
-
- return true;
- });
+ var libraryItems = GetItemsForLatestItems(user, request);
var list = new List<Tuple<BaseItem, List<BaseItem>>>();
@@ -254,8 +238,13 @@ namespace MediaBrowser.Server.Implementations.Library
return list;
}
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit)
+ private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request)
{
+ var parentId = request.ParentId;
+
+ var includeItemTypes = request.IncludeItemTypes;
+ var limit = request.Limit ?? 10;
+
var parentIds = string.IsNullOrEmpty(parentId)
? new string[] { }
: new[] { parentId };
@@ -276,7 +265,12 @@ namespace MediaBrowser.Server.Implementations.Library
var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
{
- typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name
+ typeof(Person).Name,
+ typeof(Studio).Name,
+ typeof(Year).Name,
+ typeof(GameGenre).Name,
+ typeof(MusicGenre).Name,
+ typeof(Genre).Name
} : new string[] { };
@@ -288,8 +282,9 @@ namespace MediaBrowser.Server.Implementations.Library
IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
ExcludeItemTypes = excludeItemTypes,
ExcludeLocationTypes = new[] { LocationType.Virtual },
- Limit = limit * 20,
- ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { }
+ Limit = limit * 5,
+ ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { },
+ IsPlayed = request.IsPlayed
}, parentIds);
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
index dccc7aa93..23560b1aa 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
- if (service != null)
+ if (service != null && !item.HasImage(ImageType.Primary))
{
try
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 6e5e8298f..2d2d18524 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -35,7 +35,7 @@ using Microsoft.Win32;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
- public class EmbyTV : ILiveTvService, IHasRegistrationInfo, IDisposable
+ public class EmbyTV : ILiveTvService, ISupportsNewTimerIds, IHasRegistrationInfo, IDisposable
{
private readonly IApplicationHost _appHpst;
private readonly ILogger _logger;
@@ -382,6 +382,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return list;
}
+ public async Task<List<ChannelInfo>> GetChannelsForListingsProvider(ListingsProviderInfo listingsProvider, CancellationToken cancellationToken)
+ {
+ var list = new List<ChannelInfo>();
+
+ foreach (var hostInstance in _liveTvManager.TunerHosts)
+ {
+ try
+ {
+ var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
+
+ list.AddRange(channels);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting channels", ex);
+ }
+ }
+
+ return list
+ .Where(i => IsListingProviderEnabledForTuner(listingsProvider, i.TunerHostId))
+ .ToList();
+ }
+
public Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken)
{
return GetChannelsAsync(false, cancellationToken);
@@ -435,12 +458,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
{
+ return CreateTimer(info, cancellationToken);
+ }
+
+ public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+ {
+ return CreateSeriesTimer(info, cancellationToken);
+ }
+
+ public Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken)
+ {
info.Id = Guid.NewGuid().ToString("N");
_timerProvider.Add(info);
- return Task.FromResult(0);
+ return Task.FromResult(info.Id);
}
- public async Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
+ public async Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken)
{
info.Id = Guid.NewGuid().ToString("N");
@@ -470,6 +503,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_seriesTimerProvider.Add(info);
await UpdateTimersForSeriesTimer(epgData, info, false).ConfigureAwait(false);
+
+ return info.Id;
}
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
@@ -625,7 +660,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty);
- var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken)
+ var channelMappings = GetChannelMappings(provider.Item2);
+ var channelNumber = channel.Number;
+ string mappedChannelNumber;
+ if (channelMappings.TryGetValue(channelNumber, out mappedChannelNumber))
+ {
+ _logger.Debug("Found mapped channel on provider {0}. Tuner channel number: {1}, Mapped channel number: {2}", provider.Item1.Name, channelNumber, mappedChannelNumber);
+ channelNumber = mappedChannelNumber;
+ }
+
+ var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
var list = programs.ToList();
@@ -647,6 +691,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return new List<ProgramInfo>();
}
+ private Dictionary<string, string> GetChannelMappings(ListingsProviderInfo info)
+ {
+ var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var mapping in info.ChannelMappings)
+ {
+ dict[mapping.Name] = mapping.Value;
+ }
+
+ return dict;
+ }
+
private List<Tuple<IListingsProvider, ListingsProviderInfo>> GetListingProviders()
{
return GetConfiguration().ListingProviders
@@ -954,6 +1010,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
Action onStarted = () =>
{
+ timer.Status = RecordingStatus.InProgress;
+ _timerProvider.AddOrUpdate(timer, false);
+
result.Item3.Release();
isResourceOpen = false;
};
@@ -979,7 +1038,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
result.Item3.Release();
}
- _libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
+ _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
}
}
catch (OperationCanceledException)
@@ -1000,6 +1059,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (recordingStatus == RecordingStatus.Completed)
{
+ timer.Status = RecordingStatus.Completed;
+ _timerProvider.AddOrUpdate(timer, false);
+
OnSuccessfulRecording(info.IsSeries, recordPath);
_timerProvider.Delete(timer);
}
@@ -1008,7 +1070,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
const int retryIntervalSeconds = 60;
_logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
- _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
+ timer.Status = RecordingStatus.New;
+ timer.StartDate = DateTime.UtcNow.AddSeconds(retryIntervalSeconds);
+ _timerProvider.AddOrUpdate(timer);
}
else
{
@@ -1060,7 +1124,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (regInfo.IsValid)
{
- return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config);
+ return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config, _httpClient);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index e9ea49fa3..cad300fac 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -8,7 +8,9 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -22,8 +24,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
+ private readonly IHttpClient _httpClient;
private readonly IMediaEncoder _mediaEncoder;
- private readonly IApplicationPaths _appPaths;
+ private readonly IServerApplicationPaths _appPaths;
private readonly LiveTvOptions _liveTvOptions;
private bool _hasExited;
private Stream _logFileStream;
@@ -32,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly IJsonSerializer _json;
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
- public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions)
+ public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IServerApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions, IHttpClient httpClient)
{
_logger = logger;
_fileSystem = fileSystem;
@@ -40,39 +43,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_appPaths = appPaths;
_json = json;
_liveTvOptions = liveTvOptions;
+ _httpClient = httpClient;
}
public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
{
- if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings)
- {
- // if the audio is aac_latm, stream copying to mp4 will fail
- var streams = mediaSource.MediaStreams ?? new List<MediaStream>();
- if (streams.Any(i => i.Type == MediaStreamType.Audio && (i.Codec ?? string.Empty).IndexOf("aac", StringComparison.OrdinalIgnoreCase) != -1))
- {
- return Path.ChangeExtension(targetFile, ".mkv");
- }
- }
-
return Path.ChangeExtension(targetFile, ".mp4");
}
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
- if (mediaSource.RunTimeTicks.HasValue)
+ var tempfile = Path.Combine(_appPaths.TranscodingTempPath, Guid.NewGuid().ToString("N") + ".ts");
+
+ try
{
- // The media source already has a fixed duration
- // But add another stop 1 minute later just in case the recording gets stuck for any reason
- var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ await RecordInternal(mediaSource, tempfile, targetFile, duration, onStarted, cancellationToken)
+ .ConfigureAwait(false);
}
- else
+ finally
+ {
+ File.Delete(tempfile);
+ }
+ }
+
+ public async Task RecordInternal(MediaSourceInfo mediaSource, string tempFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ {
+ var httpRequestOptions = new HttpRequestOptions()
+ {
+ Url = mediaSource.Path
+ };
+
+ httpRequestOptions.BufferContent = false;
+
+ using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
{
- // The media source if infinite so we need to handle stopping ourselves
- var durationToken = new CancellationTokenSource(duration);
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ _logger.Info("Opened recording stream from tuner provider");
+
+ Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
+
+ using (var output = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ //onStarted();
+
+ _logger.Info("Copying recording stream to file {0}", tempFile);
+
+ var bufferMs = 5000;
+
+ if (mediaSource.RunTimeTicks.HasValue)
+ {
+ // The media source already has a fixed duration
+ // But add another stop 1 minute later just in case the recording gets stuck for any reason
+ var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ }
+ else
+ {
+ // The media source if infinite so we need to handle stopping ourselves
+ var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMilliseconds(bufferMs)));
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ }
+
+ var tempFileTask = response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, cancellationToken);
+
+ // Give the temp file a little time to build up
+ await Task.Delay(bufferMs, cancellationToken).ConfigureAwait(false);
+
+ var recordTask = Task.Run(() => RecordFromFile(mediaSource, tempFile, targetFile, duration, onStarted, cancellationToken), cancellationToken);
+
+ await tempFileTask.ConfigureAwait(false);
+
+ await recordTask.ConfigureAwait(false);
+ }
}
+ _logger.Info("Recording completed to file {0}", targetFile);
+ }
+
+ private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ {
_targetPath = targetFile;
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
@@ -89,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
RedirectStandardInput = true,
FileName = _mediaEncoder.EncoderPath,
- Arguments = GetCommandLineArgs(mediaSource, targetFile, duration),
+ Arguments = GetCommandLineArgs(mediaSource, inputFile, targetFile, duration),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
@@ -110,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
- await _logFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationToken).ConfigureAwait(false);
+ _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length);
process.Exited += (sender, args) => OnFfMpegProcessExited(process);
@@ -126,10 +174,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
StartStreamingLog(process.StandardError.BaseStream, _logFileStream);
- await _taskCompletionSource.Task.ConfigureAwait(false);
+ return _taskCompletionSource.Task;
}
- private string GetCommandLineArgs(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration)
+ private string GetCommandLineArgs(MediaSourceInfo mediaSource, string inputTempFile, string targetFile, TimeSpan duration)
{
string videoArgs;
if (EncodeVideo(mediaSource))
@@ -145,23 +193,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
videoArgs = "-codec:v:0 copy";
}
- var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\" -t {4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
+ var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
+ var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -re -i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
if (mediaSource.ReadAtNativeFramerate)
{
commandLineArgs = "-re " + commandLineArgs;
}
- commandLineArgs = string.Format(commandLineArgs, mediaSource.Path, targetFile, videoArgs, GetAudioArgs(mediaSource), _mediaEncoder.GetTimeParameter(duration.Ticks));
+ commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), durationParam);
return commandLineArgs;
}
private string GetAudioArgs(MediaSourceInfo mediaSource)
{
- var copyAudio = new[] { "aac", "mp3" };
+ // do not copy aac because many players have difficulty with aac_latm
+ var copyAudio = new[] { "mp3" };
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
- if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
+ var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty;
+
+ if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase))
+ {
+ return "-codec:a:0 copy";
+ }
+ if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{
return "-codec:a:0 copy";
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 5d462f106..423358906 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -10,6 +10,7 @@ using System.Linq;
using System.Threading;
using CommonIO;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -71,6 +72,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
+ public void AddOrUpdate(TimerInfo item, bool resetTimer)
+ {
+ if (resetTimer)
+ {
+ AddOrUpdate(item);
+ return;
+ }
+
+ var list = GetAll().ToList();
+
+ if (!list.Any(i => EqualityComparer(i, item)))
+ {
+ base.Add(item);
+ }
+ else
+ {
+ base.Update(item);
+ }
+ }
+
public override void Add(TimerInfo item)
{
if (string.IsNullOrWhiteSpace(item.Id))
@@ -85,6 +106,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void AddTimer(TimerInfo item)
{
+ if (item.Status == RecordingStatus.Completed)
+ {
+ return;
+ }
+
var startDate = RecordingHelper.GetStartTime(item);
var now = DateTime.UtcNow;
@@ -117,15 +143,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- public void StartTimer(TimerInfo item, TimeSpan length)
+ public void StartTimer(TimerInfo item, TimeSpan dueTime)
{
StopTimer(item);
- var timer = new Timer(TimerCallback, item.Id, length, TimeSpan.Zero);
+ var timer = new Timer(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
if (_timers.TryAdd(item.Id, timer))
{
- _logger.Info("Creating recording timer for {0}, {1}. Timer will fire in {2} minutes", item.Id, item.Name, length.TotalMinutes.ToString(CultureInfo.InvariantCulture));
+ _logger.Info("Creating recording timer for {0}, {1}. Timer will fire in {2} minutes", item.Id, item.Name, dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
}
else
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index ae2a85090..e37109c14 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -506,8 +506,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
- ListingsProviderInfo info,
- List<string> programIds,
+ ListingsProviderInfo info,
+ List<string> programIds,
CancellationToken cancellationToken)
{
var imageIdString = "[";
@@ -564,7 +564,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
- using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
+ using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.Headends>>(responce);
@@ -666,58 +666,60 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
}
- private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
+ private async Task<HttpResponseInfo> Post(HttpRequestOptions options,
+ bool enableRetry,
+ ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Post(options).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry) {
- throw;
- }
- }
-
- var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
- options.RequestHeaders ["token"] = newToken;
- return await Post (options, false, providerInfo).ConfigureAwait (false);
+ }
+ catch (HttpException ex)
+ {
+ _tokens.Clear();
+
+ if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
+ {
+ enableRetry = false;
+ }
+
+ if (!enableRetry)
+ {
+ throw;
+ }
+ }
+
+ var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
+ options.RequestHeaders["token"] = newToken;
+ return await Post(options, false, providerInfo).ConfigureAwait(false);
}
- private async Task<Stream> Get(HttpRequestOptions options,
- bool enableRetry,
- ListingsProviderInfo providerInfo)
+ private async Task<Stream> Get(HttpRequestOptions options,
+ bool enableRetry,
+ ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Get(options).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- _tokens.Clear();
-
- if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
- {
- enableRetry = false;
- }
-
- if (!enableRetry) {
- throw;
- }
- }
-
- var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false);
- options.RequestHeaders ["token"] = newToken;
- return await Get (options, false, providerInfo).ConfigureAwait (false);
+ }
+ catch (HttpException ex)
+ {
+ _tokens.Clear();
+
+ if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
+ {
+ enableRetry = false;
+ }
+
+ if (!enableRetry)
+ {
+ throw;
+ }
+ }
+
+ var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
+ options.RequestHeaders["token"] = newToken;
+ return await Get(options, false, providerInfo).ConfigureAwait(false);
}
private async Task<string> GetTokenInternal(string username, string password,
@@ -734,7 +736,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
//_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
- using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
+ using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Token>(responce.Content);
if (root.message == "OK")
@@ -816,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
try
{
- using (var response = await Get(options, false, null).ConfigureAwait(false))
+ using (var response = await Get(options, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(response);
@@ -869,6 +871,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return GetHeadends(info, country, location, CancellationToken.None);
}
+ public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+ {
+ var listingsId = info.ListingsId;
+ if (string.IsNullOrWhiteSpace(listingsId))
+ {
+ throw new Exception("ListingsId required");
+ }
+
+ await AddMetadata(info, new List<ChannelInfo>(), cancellationToken).ConfigureAwait(false);
+
+ var token = await GetToken(info, cancellationToken);
+
+ if (string.IsNullOrWhiteSpace(token))
+ {
+ throw new Exception("token required");
+ }
+
+ var httpOptions = new HttpRequestOptions()
+ {
+ Url = ApiUrl + "/lineups/" + listingsId,
+ UserAgent = UserAgent,
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true,
+ // The data can be large so give it some extra time
+ TimeoutMs = 60000
+ };
+
+ httpOptions.RequestHeaders["token"] = token;
+
+ var list = new List<ChannelInfo>();
+
+ using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
+ {
+ var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
+ _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
+ _logger.Info("Mapping Stations to Channel");
+ foreach (ScheduleDirect.Map map in root.map)
+ {
+ var channelNumber = map.logicalChannelNumber;
+
+ if (string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channelNumber = map.channel;
+ }
+ if (string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channelNumber = map.atscMajor + "." + map.atscMinor;
+ }
+ channelNumber = channelNumber.TrimStart('0');
+
+ var name = channelNumber;
+ var station = GetStation(listingsId, channelNumber, null);
+
+ if (station != null)
+ {
+ name = station.name;
+ }
+
+ list.Add(new ChannelInfo
+ {
+ Number = channelNumber,
+ Name = name
+ });
+ }
+ }
+
+ return list;
+ }
+
public class ScheduleDirect
{
public class Token
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
deleted file mode 100644
index ac316f9a1..000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.LiveTv;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.Listings
-{
- public class XmlTv : IListingsProvider
- {
- public string Name
- {
- get { return "XmlTV"; }
- }
-
- public string Type
- {
- get { return "xmltv"; }
- }
-
- public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
-
- public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
- {
- // Might not be needed
- }
-
- public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
- {
- // Check that the path or url is valid. If not, throw a file not found exception
- }
-
- public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
- {
- // In theory this should never be called because there is always only one lineup
- throw new NotImplementedException();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
new file mode 100644
index 000000000..14e4e1093
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -0,0 +1,200 @@
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.XmlTv.Classes;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.LiveTv.Listings
+{
+ public class XmlTvListingsProvider : IListingsProvider
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IHttpClient _httpClient;
+ private readonly ILogger _logger;
+
+ public XmlTvListingsProvider(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
+ {
+ _config = config;
+ _httpClient = httpClient;
+ _logger = logger;
+ }
+
+ public string Name
+ {
+ get { return "XmlTV"; }
+ }
+
+ public string Type
+ {
+ get { return "xmltv"; }
+ }
+
+ private string GetLanguage()
+ {
+ return _config.Configuration.PreferredMetadataLanguage;
+ }
+
+ private async Task<string> GetXml(string path, CancellationToken cancellationToken)
+ {
+ _logger.Info("xmltv path: {0}", path);
+
+ if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ {
+ return path;
+ }
+
+ var cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml";
+ var cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename);
+ if (File.Exists(cacheFile))
+ {
+ return cacheFile;
+ }
+
+ _logger.Info("Downloading xmltv listings from {0}", path);
+
+ var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
+ {
+ CancellationToken = cancellationToken,
+ Url = path,
+ Progress = new Progress<Double>(),
+ DecompressionMethod = DecompressionMethods.GZip,
+
+ // It's going to come back gzipped regardless of this value
+ // So we need to make sure the decompression method is set to gzip
+ EnableHttpCompression = true
+
+ }).ConfigureAwait(false);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
+
+ using (var stream = File.OpenRead(tempFile))
+ {
+ using (var reader = new StreamReader(stream, Encoding.UTF8))
+ {
+ using (var fileStream = File.OpenWrite(cacheFile))
+ {
+ using (var writer = new StreamWriter(fileStream))
+ {
+ while (!reader.EndOfStream)
+ {
+ writer.WriteLine(reader.ReadLine());
+ }
+ }
+ }
+ }
+ }
+
+ _logger.Debug("Returning xmltv path {0}", cacheFile);
+ return cacheFile;
+ }
+
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ {
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+
+ var results = reader.GetProgrammes(channelNumber, startDateUtc, endDateUtc, cancellationToken);
+ return results.Select(p => new ProgramInfo()
+ {
+ ChannelId = p.ChannelId,
+ EndDate = p.EndDate,
+ EpisodeNumber = p.Episode == null ? null : p.Episode.Episode,
+ EpisodeTitle = p.Episode == null ? null : p.Episode.Title,
+ Genres = p.Categories,
+ Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date,
+ StartDate = p.StartDate,
+ Name = p.Title,
+ Overview = p.Description,
+ ShortOverview = p.Description,
+ ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year,
+ SeasonNumber = p.Episode == null ? null : p.Episode.Series,
+ IsSeries = p.Episode != null,
+ IsRepeat = p.IsRepeat,
+ IsPremiere = p.Premiere != null,
+ IsKids = p.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsMovie = p.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsNews = p.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ IsSports = p.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)),
+ ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null,
+ HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source),
+ OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null,
+ CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null,
+ SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null
+ });
+ }
+
+ public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken)
+ {
+ // Add the channel image url
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels().ToList();
+
+ if (channels != null)
+ {
+ channels.ForEach(c =>
+ {
+ var channelNumber = info.GetMappedChannel(c.Number);
+ var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase));
+
+ if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
+ {
+ c.ImageUrl = match.Icon.Source;
+ }
+ });
+ }
+ }
+
+ public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
+ {
+ // Assume all urls are valid. check files for existence
+ if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase) && !File.Exists(info.Path))
+ {
+ throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path);
+ }
+
+ return Task.FromResult(true);
+ }
+
+ public async Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
+ {
+ // In theory this should never be called because there is always only one lineup
+ var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels();
+
+ // Should this method be async?
+ return results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList();
+ }
+
+ public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+ {
+ // In theory this should never be called because there is always only one lineup
+ var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
+ var reader = new XmlTvReader(path, GetLanguage(), null);
+ var results = reader.GetChannels();
+
+ // Should this method be async?
+ return results.Select(c => new ChannelInfo()
+ {
+ Id = c.Id,
+ Name = c.DisplayName,
+ ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null,
+ Number = c.Id
+
+ }).ToList();
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index e126e5411..95ed2aac1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -30,6 +30,8 @@ using System.Threading.Tasks;
using CommonIO;
using IniParser;
using IniParser.Model;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Model.Events;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@@ -64,6 +66,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
private readonly IFileSystem _fileSystem;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+ public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
+
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
{
_config = config;
@@ -133,10 +140,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
+ var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
+
var channels = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
- SortBy = new[] { ItemSortBy.SortName }
+ SortBy = new[] { ItemSortBy.SortName },
+ TopParentIds = new[] { topFolder.Id.ToString("N") }
}).Cast<LiveTvChannel>();
@@ -884,6 +894,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
+ var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
+
+ if (query.SortBy.Length == 0)
+ {
+ // Unless something else was specified, order by start date to take advantage of a specialized index
+ query.SortBy = new[] { ItemSortBy.StartDate };
+ }
+
var internalQuery = new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
@@ -900,7 +918,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
Limit = query.Limit,
SortBy = query.SortBy,
SortOrder = query.SortOrder ?? SortOrder.Ascending,
- EnableTotalRecordCount = query.EnableTotalRecordCount
+ EnableTotalRecordCount = query.EnableTotalRecordCount,
+ TopParentIds = new[] { topFolder.Id.ToString("N") }
};
if (query.HasAired.HasValue)
@@ -917,7 +936,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var queryResult = _libraryManager.QueryItems(internalQuery);
- var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ToArray();
+ var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
{
@@ -932,6 +951,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var user = _userManager.GetUserById(query.UserId);
+ var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
+
var internalQuery = new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
@@ -940,12 +961,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
IsSports = query.IsSports,
IsKids = query.IsKids,
EnableTotalRecordCount = query.EnableTotalRecordCount,
- SortBy = new[] { ItemSortBy.StartDate }
+ SortBy = new[] { ItemSortBy.StartDate },
+ TopParentIds = new[] { topFolder.Id.ToString("N") }
};
if (query.Limit.HasValue)
{
- internalQuery.Limit = Math.Max(query.Limit.Value * 5, 300);
+ internalQuery.Limit = Math.Max(query.Limit.Value * 4, 200);
}
if (query.HasAired.HasValue)
@@ -994,7 +1016,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var user = _userManager.GetUserById(query.UserId);
- var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ToArray();
+ var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
{
@@ -1398,7 +1420,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
ExcludeLocationTypes = new[] { LocationType.Virtual },
Limit = Math.Min(200, query.Limit ?? int.MaxValue),
SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending
+ SortOrder = SortOrder.Descending,
+ EnableTotalRecordCount = query.EnableTotalRecordCount
});
}
@@ -1631,7 +1654,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false);
- var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ToArray();
+ var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
return new QueryResult<BaseItemDto>
{
@@ -1658,6 +1681,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
var timers = results.SelectMany(i => i.ToList());
+ if (query.IsActive.HasValue)
+ {
+ if (query.IsActive.Value)
+ {
+ timers = timers.Where(i => i.Item1.Status == RecordingStatus.InProgress);
+ }
+ else
+ {
+ timers = timers.Where(i => i.Item1.Status != RecordingStatus.InProgress);
+ }
+ }
+
if (!string.IsNullOrEmpty(query.ChannelId))
{
var guid = new Guid(query.ChannelId);
@@ -1759,6 +1794,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ Id = id
+ }
+ }, _logger);
}
public async Task CancelSeriesTimer(string id)
@@ -1774,6 +1817,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ Id = id
+ }
+ }, _logger);
}
public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
@@ -1870,7 +1921,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
MaxStartDate = now,
MinEndDate = now,
Limit = channelIds.Length,
- SortBy = new[] { "StartDate" }
+ SortBy = new[] { "StartDate" },
+ TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }
}, new string[] { }).ToList();
@@ -1990,9 +2042,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var defaultValues = await service.GetNewTimerDefaultsAsync(cancellationToken).ConfigureAwait(false);
info.Priority = defaultValues.Priority;
- await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ string newTimerId = null;
+ var supportsNewTimerIds = service as ISupportsNewTimerIds;
+ if (supportsNewTimerIds != null)
+ {
+ newTimerId = await supportsNewTimerIds.CreateTimer(info, cancellationToken).ConfigureAwait(false);
+ newTimerId = _tvDtoService.GetInternalTimerId(timer.ServiceName, newTimerId).ToString("N");
+ }
+ else
+ {
+ await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ }
+
_lastRecordingRefreshTime = DateTime.MinValue;
_logger.Info("New recording scheduled");
+
+ EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ ProgramId = _tvDtoService.GetInternalProgramId(timer.ServiceName, info.ProgramId).ToString("N"),
+ Id = newTimerId
+ }
+ }, _logger);
}
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
@@ -2005,8 +2077,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var defaultValues = await service.GetNewTimerDefaultsAsync(cancellationToken).ConfigureAwait(false);
info.Priority = defaultValues.Priority;
- await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ string newTimerId = null;
+ var supportsNewTimerIds = service as ISupportsNewTimerIds;
+ if (supportsNewTimerIds != null)
+ {
+ newTimerId = await supportsNewTimerIds.CreateSeriesTimer(info, cancellationToken).ConfigureAwait(false);
+ newTimerId = _tvDtoService.GetInternalSeriesTimerId(timer.ServiceName, newTimerId).ToString("N");
+ }
+ else
+ {
+ await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
+ }
+
_lastRecordingRefreshTime = DateTime.MinValue;
+
+ EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ {
+ Argument = new TimerEventInfo
+ {
+ ProgramId = _tvDtoService.GetInternalProgramId(timer.ServiceName, info.ProgramId).ToString("N"),
+ Id = newTimerId
+ }
+ }, _logger);
}
public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
@@ -2521,5 +2613,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
return new TunerHosts.SatIp.ChannelScan(_logger).Scan(info, cancellationToken);
}
+
+ public Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken)
+ {
+ var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+ return EmbyTV.EmbyTV.Current.GetChannelsForListingsProvider(info, cancellationToken);
+ }
+
+ public Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken)
+ {
+ var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+ var provider = _listingProviders.First(i => string.Equals(i.Type, info.Type, StringComparison.OrdinalIgnoreCase));
+ return provider.GetChannels(info, cancellationToken);
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index d3bb87bc7..cdba1873e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
var list = sources.ToList();
- var serverUrl = _appHost.LocalApiUrl;
+ var serverUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
foreach (var source in list)
{
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 5b3419639..cfe0564fb 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -46,7 +46,7 @@
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
</Reference>
<Reference Include="Emby.XmlTv, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\Emby.XmlTv.1.0.0.50\lib\net45\Emby.XmlTv.dll</HintPath>
+ <HintPath>..\packages\Emby.XmlTv.1.0.0.53\lib\net45\Emby.XmlTv.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="INIFileParser, Version=2.3.0.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
@@ -56,8 +56,8 @@
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.5996.42016, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.51\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ <Reference Include="MediaBrowser.Naming, Version=1.0.6012.15754, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.52\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MoreLinq">
@@ -142,6 +142,7 @@
<Compile Include="EntryPoints\LoadRegistrations.cs" />
<Compile Include="EntryPoints\Notifications\Notifications.cs" />
<Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" />
+ <Compile Include="EntryPoints\RecordingNotifier.cs" />
<Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
<Compile Include="EntryPoints\UsageEntryPoint.cs" />
<Compile Include="Connect\ConnectEntryPoint.cs" />
@@ -233,7 +234,7 @@
<Compile Include="LiveTv\EmbyTV\SeriesTimerManager.cs" />
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
- <Compile Include="LiveTv\Listings\XmlTv.cs" />
+ <Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
<Compile Include="LiveTv\LiveTvDtoService.cs" />
<Compile Include="LiveTv\LiveTvManager.cs" />
@@ -391,7 +392,103 @@
<EmbeddedResource Include="Localization\Ratings\ru.txt" />
</ItemGroup>
<ItemGroup>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\backbone-min.js">
+ <Link>swagger-ui\lib\backbone-min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\handlebars-2.0.0.js">
+ <Link>swagger-ui\lib\handlebars-2.0.0.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\highlight.7.3.pack.js">
+ <Link>swagger-ui\lib\highlight.7.3.pack.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery-1.8.0.min.js">
+ <Link>swagger-ui\lib\jquery-1.8.0.min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.ba-bbq.min.js">
+ <Link>swagger-ui\lib\jquery.ba-bbq.min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.slideto.min.js">
+ <Link>swagger-ui\lib\jquery.slideto.min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.wiggle.min.js">
+ <Link>swagger-ui\lib\jquery.wiggle.min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\marked.js">
+ <Link>swagger-ui\lib\marked.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\shred.bundle.js">
+ <Link>swagger-ui\lib\shred.bundle.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\swagger-client.js">
+ <Link>swagger-ui\lib\swagger-client.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\swagger-oauth.js">
+ <Link>swagger-ui\lib\swagger-oauth.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\underscore-min.js">
+ <Link>swagger-ui\lib\underscore-min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\o2c.html">
+ <Link>swagger-ui\o2c.html</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\patch.js">
+ <Link>swagger-ui\patch.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\swagger-ui.js">
+ <Link>swagger-ui\swagger-ui.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\swagger-ui.min.js">
+ <Link>swagger-ui\swagger-ui.min.js</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<EmbeddedResource Include="Localization\countries.json" />
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-700.eot">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-700.eot</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-700.ttf">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-700.ttf</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-700.woff">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-700.woff</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-700.woff2">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-700.woff2</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-regular.eot">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-regular.eot</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-regular.ttf">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-regular.ttf</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-regular.woff">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-regular.woff</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-regular.woff2">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-regular.woff2</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<None Include="app.config" />
<EmbeddedResource Include="Localization\Core\core.json" />
<EmbeddedResource Include="Localization\Core\ar.json" />
@@ -608,10 +705,30 @@
<EmbeddedResource Include="Localization\Ratings\ca.txt" />
</ItemGroup>
<ItemGroup>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\css\reset.css">
+ <Link>swagger-ui\css\reset.css</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="..\ThirdParty\ServiceStack\swagger-ui\css\screen.css">
<Link>swagger-ui\css\screen.css</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\css\typography.css">
+ <Link>swagger-ui\css\typography.css</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-700.svg">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-700.svg</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\fonts\droid-sans-v6-latin-regular.svg">
+ <Link>swagger-ui\fonts\droid-sans-v6-latin-regular.svg</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\ThirdParty\ServiceStack\swagger-ui\images\explorer_icons.png">
+ <Link>swagger-ui\images\explorer_icons.png</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="..\ThirdParty\ServiceStack\swagger-ui\images\logo_small.png">
<Link>swagger-ui\images\logo_small.png</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -632,58 +749,10 @@
<Link>swagger-ui\index.html</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\backbone-min.js">
- <Link>swagger-ui\lib\backbone-min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\handlebars-1.0.0.js">
- <Link>swagger-ui\lib\handlebars-1.0.0.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\highlight.7.3.pack.js">
- <Link>swagger-ui\lib\highlight.7.3.pack.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery-1.8.0.min.js">
- <Link>swagger-ui\lib\jquery-1.8.0.min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.ba-bbq.min.js">
- <Link>swagger-ui\lib\jquery.ba-bbq.min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.slideto.min.js">
- <Link>swagger-ui\lib\jquery.slideto.min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\jquery.wiggle.min.js">
- <Link>swagger-ui\lib\jquery.wiggle.min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\shred.bundle.js">
- <Link>swagger-ui\lib\shred.bundle.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\shred\content.js">
<Link>swagger-ui\lib\shred\content.js</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\swagger.js">
- <Link>swagger-ui\lib\swagger.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\lib\underscore-min.js">
- <Link>swagger-ui\lib\underscore-min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\swagger-ui.js">
- <Link>swagger-ui\swagger-ui.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\ThirdParty\ServiceStack\swagger-ui\swagger-ui.min.js">
- <Link>swagger-ui\swagger-ui.min.js</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<EmbeddedResource Include="Localization\iso6392.txt" />
<EmbeddedResource Include="Localization\Ratings\be.txt" />
</ItemGroup>
diff --git a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 10e8c5699..be8c6d48d 100644
--- a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -15,74 +15,28 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
public class SqliteNotificationsRepository : BaseSqliteRepository, INotificationsRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
+ public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector dbConnector) : base(logManager, dbConnector)
+ {
+ DbFilePath = Path.Combine(appPaths.DataPath, "notifications.db");
+ }
public event EventHandler<NotificationUpdateEventArgs> NotificationAdded;
public event EventHandler<NotificationReadEventArgs> NotificationsMarkedRead;
public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated;
- private IDbCommand _replaceNotificationCommand;
- private IDbCommand _markReadCommand;
- private IDbCommand _markAllReadCommand;
-
- public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public async Task Initialize()
{
- _appPaths = appPaths;
- }
-
- public async Task Initialize(IDbConnector dbConnector)
- {
- var dbFile = Path.Combine(_appPaths.DataPath, "notifications.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists Notifications (Id GUID NOT NULL, UserId GUID NOT NULL, Date DATETIME NOT NULL, Name TEXT NOT NULL, Description TEXT, Url TEXT, Level TEXT NOT NULL, IsRead BOOLEAN NOT NULL, Category TEXT NOT NULL, RelatedId TEXT, PRIMARY KEY (Id, UserId))",
"create index if not exists idx_Notifications1 on Notifications(Id)",
- "create index if not exists idx_Notifications2 on Notifications(UserId)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_Notifications2 on Notifications(UserId)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _replaceNotificationCommand = _connection.CreateCommand();
- _replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)";
-
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Id");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Date");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Name");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Description");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Url");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Level");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Category");
- _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@RelatedId");
-
- _markReadCommand = _connection.CreateCommand();
- _markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId";
-
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
- _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@Id");
-
- _markAllReadCommand = _connection.CreateCommand();
- _markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId";
-
- _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId");
- _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead");
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -94,49 +48,52 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
var result = new NotificationResult();
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- var clauses = new List<string>();
-
- if (query.IsRead.HasValue)
+ using (var cmd = connection.CreateCommand())
{
- clauses.Add("IsRead=@IsRead");
- cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value;
- }
+ var clauses = new List<string>();
- clauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId);
+ if (query.IsRead.HasValue)
+ {
+ clauses.Add("IsRead=@IsRead");
+ cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value;
+ }
- var whereClause = " where " + string.Join(" And ", clauses.ToArray());
+ clauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId);
- cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
+ var whereClause = " where " + string.Join(" And ", clauses.ToArray());
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- if (reader.Read())
- {
- result.TotalRecordCount = reader.GetInt32(0);
- }
+ cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
- if (reader.NextResult())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- var notifications = GetNotifications(reader);
-
- if (query.StartIndex.HasValue)
+ if (reader.Read())
{
- notifications = notifications.Skip(query.StartIndex.Value);
+ result.TotalRecordCount = reader.GetInt32(0);
}
- if (query.Limit.HasValue)
+ if (reader.NextResult())
{
- notifications = notifications.Take(query.Limit.Value);
- }
+ var notifications = GetNotifications(reader);
+
+ if (query.StartIndex.HasValue)
+ {
+ notifications = notifications.Skip(query.StartIndex.Value);
+ }
+
+ if (query.Limit.HasValue)
+ {
+ notifications = notifications.Take(query.Limit.Value);
+ }
- result.Notifications = notifications.ToArray();
+ result.Notifications = notifications.ToArray();
+ }
}
- }
- return result;
+ return result;
+ }
}
}
@@ -144,31 +101,34 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
var result = new NotificationsSummary();
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead";
-
- cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId);
- cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ using (var cmd = connection.CreateCommand())
{
- var levels = new List<NotificationLevel>();
+ cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead";
- while (reader.Read())
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId);
+ cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- levels.Add(GetLevel(reader, 0));
- }
+ var levels = new List<NotificationLevel>();
+
+ while (reader.Read())
+ {
+ levels.Add(GetLevel(reader, 0));
+ }
- result.UnreadCount = levels.Count;
+ result.UnreadCount = levels.Count;
- if (levels.Count > 0)
- {
- result.MaxUnreadNotificationLevel = levels.Max();
+ if (levels.Count > 0)
+ {
+ result.MaxUnreadNotificationLevel = levels.Max();
+ }
}
- }
- return result;
+ return result;
+ }
}
}
@@ -179,10 +139,14 @@ namespace MediaBrowser.Server.Implementations.Notifications
/// <returns>IEnumerable{Notification}.</returns>
private IEnumerable<Notification> GetNotifications(IDataReader reader)
{
+ var list = new List<Notification>();
+
while (reader.Read())
{
- yield return GetNotification(reader);
+ list.Add(GetNotification(reader));
}
+
+ return list;
}
private Notification GetNotification(IDataReader reader)
@@ -273,59 +237,74 @@ namespace MediaBrowser.Server.Implementations.Notifications
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ using (var replaceNotificationCommand = connection.CreateCommand())
+ {
+ replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)";
+
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Id");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@UserId");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Date");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Name");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Description");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Url");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Level");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@IsRead");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Category");
+ replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@RelatedId");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
- _replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id);
- _replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId);
- _replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime();
- _replaceNotificationCommand.GetParameter(3).Value = notification.Name;
- _replaceNotificationCommand.GetParameter(4).Value = notification.Description;
- _replaceNotificationCommand.GetParameter(5).Value = notification.Url;
- _replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString();
- _replaceNotificationCommand.GetParameter(7).Value = notification.IsRead;
- _replaceNotificationCommand.GetParameter(8).Value = string.Empty;
- _replaceNotificationCommand.GetParameter(9).Value = string.Empty;
+ replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id);
+ replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId);
+ replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime();
+ replaceNotificationCommand.GetParameter(3).Value = notification.Name;
+ replaceNotificationCommand.GetParameter(4).Value = notification.Description;
+ replaceNotificationCommand.GetParameter(5).Value = notification.Url;
+ replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString();
+ replaceNotificationCommand.GetParameter(7).Value = notification.IsRead;
+ replaceNotificationCommand.GetParameter(8).Value = string.Empty;
+ replaceNotificationCommand.GetParameter(9).Value = string.Empty;
- _replaceNotificationCommand.Transaction = transaction;
+ replaceNotificationCommand.Transaction = transaction;
- _replaceNotificationCommand.ExecuteNonQuery();
+ replaceNotificationCommand.ExecuteNonQuery();
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -366,51 +345,58 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var markAllReadCommand = connection.CreateCommand())
+ {
+ markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId";
- IDbTransaction transaction = null;
+ markAllReadCommand.Parameters.Add(markAllReadCommand, "@UserId");
+ markAllReadCommand.Parameters.Add(markAllReadCommand, "@IsRead");
- try
- {
- cancellationToken.ThrowIfCancellationRequested();
+ IDbTransaction transaction = null;
- transaction = _connection.BeginTransaction();
+ try
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- _markAllReadCommand.GetParameter(0).Value = new Guid(userId);
- _markAllReadCommand.GetParameter(1).Value = isRead;
+ transaction = connection.BeginTransaction();
- _markAllReadCommand.ExecuteNonQuery();
+ markAllReadCommand.GetParameter(0).Value = new Guid(userId);
+ markAllReadCommand.GetParameter(1).Value = isRead;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ markAllReadCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
@@ -418,72 +404,66 @@ namespace MediaBrowser.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- cancellationToken.ThrowIfCancellationRequested();
+ using (var markReadCommand = connection.CreateCommand())
+ {
+ markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId";
- transaction = _connection.BeginTransaction();
+ markReadCommand.Parameters.Add(markReadCommand, "@UserId");
+ markReadCommand.Parameters.Add(markReadCommand, "@IsRead");
+ markReadCommand.Parameters.Add(markReadCommand, "@Id");
- _markReadCommand.GetParameter(0).Value = new Guid(userId);
- _markReadCommand.GetParameter(1).Value = isRead;
+ IDbTransaction transaction = null;
- foreach (var id in notificationIdList)
- {
- _markReadCommand.GetParameter(2).Value = id;
+ try
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- _markReadCommand.Transaction = transaction;
+ transaction = connection.BeginTransaction();
- _markReadCommand.ExecuteNonQuery();
- }
+ markReadCommand.GetParameter(0).Value = new Guid(userId);
+ markReadCommand.GetParameter(1).Value = isRead;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ foreach (var id in notificationIdList)
+ {
+ markReadCommand.GetParameter(2).Value = id;
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save notification:", e);
+ markReadCommand.Transaction = transaction;
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ markReadCommand.ExecuteNonQuery();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
- }
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save notification:", e);
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- _connection.Dispose();
- _connection = null;
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
index 395907844..eec5b4b76 100644
--- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
@@ -9,13 +9,35 @@ namespace MediaBrowser.Server.Implementations.Persistence
public abstract class BaseSqliteRepository : IDisposable
{
protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1);
+ protected readonly IDbConnector DbConnector;
protected ILogger Logger;
- protected BaseSqliteRepository(ILogManager logManager)
+ protected string DbFilePath { get; set; }
+
+ protected BaseSqliteRepository(ILogManager logManager, IDbConnector dbConnector)
{
+ DbConnector = dbConnector;
Logger = logManager.GetLogger(GetType().Name);
}
+ protected virtual bool EnableConnectionPooling
+ {
+ get { return true; }
+ }
+
+ protected virtual async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, true).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory"
+
+ }, Logger);
+
+ return connection;
+ }
+
private bool _disposed;
protected void CheckDisposed()
{
@@ -84,6 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- protected abstract void CloseConnection();
+ protected virtual void CloseConnection()
+ {
+
+ }
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
index 2a2f9a09d..b11a3e496 100644
--- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
@@ -15,6 +15,7 @@ using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Net;
using MediaBrowser.Server.Implementations.ScheduledTasks;
@@ -145,7 +146,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
{
- IsCurrentSchema = false
+ IsCurrentSchema = false,
+ ExcludeItemTypes = new[] { typeof(LiveTvProgram).Name }
});
var numComplete = 0;
@@ -236,14 +238,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
// These have their own cleanup routines
ExcludeItemTypes = new[]
{
- typeof(Person).Name,
- typeof(Genre).Name,
- typeof(MusicGenre).Name,
- typeof(GameGenre).Name,
- typeof(Studio).Name,
- typeof(Year).Name,
- typeof(Channel).Name,
- typeof(AggregateFolder).Name,
+ typeof(Person).Name,
+ typeof(Genre).Name,
+ typeof(MusicGenre).Name,
+ typeof(GameGenre).Name,
+ typeof(Studio).Name,
+ typeof(Year).Name,
+ typeof(Channel).Name,
+ typeof(AggregateFolder).Name,
typeof(CollectionFolder).Name
}
});
@@ -313,8 +315,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
public IEnumerable<ITaskTrigger> GetDefaultTriggers()
{
- return new ITaskTrigger[]
- {
+ return new ITaskTrigger[]
+ {
new IntervalTrigger{ Interval = TimeSpan.FromHours(24)}
};
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
index cac9fe983..596cf8407 100644
--- a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
@@ -5,6 +5,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
public interface IDbConnector
{
- Task<IDbConnection> Connect(string dbPath);
+ Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null);
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
index 948e99cb8..1d9be2e0d 100644
--- a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
@@ -28,6 +28,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
AddNalColumn();
AddIsAvcColumn();
AddTitleColumn();
+ AddTimeBaseColumn();
+ AddCodecTimeBaseColumn();
}
private void AddIsAvcColumn()
@@ -61,6 +63,68 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.RunQueries(new[] { builder.ToString() }, _logger);
}
+ private void AddTimeBaseColumn()
+ {
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "PRAGMA table_info(mediastreams)";
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ if (!reader.IsDBNull(1))
+ {
+ var name = reader.GetString(1);
+
+ if (string.Equals(name, "TimeBase", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column TimeBase TEXT");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddCodecTimeBaseColumn()
+ {
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "PRAGMA table_info(mediastreams)";
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ if (!reader.IsDBNull(1))
+ {
+ var name = reader.GetString(1);
+
+ if (string.Equals(name, "CodecTimeBase", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column CodecTimeBase TEXT");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
private void AddTitleColumn()
{
using (var cmd = _connection.CreateCommand())
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
index 6077cfdba..40970dbe4 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
@@ -18,12 +18,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
{
- private IDbConnection _connection;
-
- public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager)
+ public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector)
+ : base(logManager, dbConnector)
{
_jsonSerializer = jsonSerializer;
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
}
/// <summary>
@@ -44,32 +43,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
private readonly IJsonSerializer _jsonSerializer;
/// <summary>
- /// The _app paths
- /// </summary>
- private readonly IApplicationPaths _appPaths;
-
- /// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists userdisplaypreferences (id GUID, userId GUID, client text, data BLOB)",
- "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -96,58 +84,57 @@ namespace MediaBrowser.Server.Implementations.Persistence
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
+ transaction = connection.BeginTransaction();
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id);
- cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client;
- cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.Transaction = transaction;
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id);
+ cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client;
+ cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
- cmd.ExecuteNonQuery();
- }
+ cmd.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ cmd.ExecuteNonQuery();
+ }
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save display preferences:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save display preferences:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -168,64 +155,63 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- foreach (var displayPreference in displayPreferences)
+ try
{
+ transaction = connection.BeginTransaction();
- var serialized = _jsonSerializer.SerializeToBytes(displayPreference);
-
- using (var cmd = _connection.CreateCommand())
+ foreach (var displayPreference in displayPreferences)
{
- cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id);
- cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client;
- cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+ var serialized = _jsonSerializer.SerializeToBytes(displayPreference);
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
- cmd.ExecuteNonQuery();
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id);
+ cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client;
+ cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+ }
}
- }
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save display preferences:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save display preferences:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -246,28 +232,33 @@ namespace MediaBrowser.Server.Implementations.Persistence
var guidId = displayPreferencesId.GetMD5();
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client";
-
- cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId;
- cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
- cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var connection = CreateConnection(true).Result)
{
- if (reader.Read())
+ using (var cmd = connection.CreateCommand())
{
- using (var stream = reader.GetMemoryStream(0))
+ cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client";
+
+ cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId;
+ cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
+ cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ if (reader.Read())
+ {
+ using (var stream = reader.GetMemoryStream(0))
+ {
+ return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ }
+ }
}
+
+ return new DisplayPreferences
+ {
+ Id = guidId.ToString("N")
+ };
}
}
-
- return new DisplayPreferences
- {
- Id = guidId.ToString("N")
- };
}
/// <summary>
@@ -278,36 +269,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <exception cref="System.ArgumentNullException">item</exception>
public IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId)
{
+ var list = new List<DisplayPreferences>();
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select data from userdisplaypreferences where userId=@userId";
-
- cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ using (var connection = CreateConnection(true).Result)
{
- while (reader.Read())
+ using (var cmd = connection.CreateCommand())
{
- using (var stream = reader.GetMemoryStream(0))
+ cmd.CommandText = "select data from userdisplaypreferences where userId=@userId";
+
+ cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
- yield return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
+ while (reader.Read())
+ {
+ using (var stream = reader.GetMemoryStream(0))
+ {
+ list.Add(_jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream));
+ }
+ }
}
}
}
- }
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
- _connection.Dispose();
- _connection = null;
- }
+ return list;
}
public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
index dd2f15cfd..d5b582da5 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
@@ -19,43 +19,40 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <summary>
/// Connects to db.
/// </summary>
- /// <param name="dbPath">The db path.</param>
- /// <param name="logger">The logger.</param>
- /// <returns>Task{IDbConnection}.</returns>
- /// <exception cref="System.ArgumentNullException">dbPath</exception>
- public static async Task<IDbConnection> ConnectToDb(string dbPath, ILogger logger)
+ public static async Task<IDbConnection> ConnectToDb(string dbPath, bool isReadOnly, bool enablePooling, int? cacheSize, ILogger logger)
{
if (string.IsNullOrEmpty(dbPath))
{
throw new ArgumentNullException("dbPath");
}
- logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath);
+ SQLiteConnection.SetMemoryStatus(false);
var connectionstr = new SQLiteConnectionStringBuilder
{
PageSize = 4096,
- CacheSize = 2000,
+ CacheSize = cacheSize ?? 2000,
SyncMode = SynchronizationModes.Normal,
DataSource = dbPath,
- JournalMode = SQLiteJournalModeEnum.Wal
+ JournalMode = SQLiteJournalModeEnum.Wal,
+
+ // This is causing crashing under linux
+ Pooling = enablePooling && Environment.OSVersion.Platform == PlatformID.Win32NT,
+ ReadOnly = isReadOnly
};
- var connection = new SQLiteConnection(connectionstr.ConnectionString);
+ var connectionString = connectionstr.ConnectionString;
+
+ if (!enablePooling)
+ {
+ logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString);
+ }
+
+ var connection = new SQLiteConnection(connectionString);
await connection.OpenAsync().ConfigureAwait(false);
return connection;
}
-
- public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function)
- {
- var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast<SQLiteFunctionAttribute>().ToArray();
- if (attributes.Length == 0)
- {
- throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute");
- }
- connection.BindFunction(attributes[0], function);
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
index 037776997..7a5e00090 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
@@ -16,74 +16,29 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
{
- private IDbConnection _connection;
-
- private readonly IServerApplicationPaths _appPaths;
-
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveResultCommand;
- private IDbCommand _deleteResultCommand;
- private IDbCommand _deleteAllCommand;
-
- public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager)
+ public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db");
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)",
- "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveResultCommand = _connection.CreateCommand();
- _saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
-
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ResultId");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OriginalPath");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@TargetPath");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@FileLength");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationDate");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@Status");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationType");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@StatusMessage");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedName");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedYear");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedSeasonNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEpisodeNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEndingEpisodeNumber");
- _saveResultCommand.Parameters.Add(_saveResultCommand, "@DuplicatePaths");
-
- _deleteResultCommand = _connection.CreateCommand();
- _deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId";
-
- _deleteResultCommand.Parameters.Add(_saveResultCommand, "@ResultId");
-
- _deleteAllCommand = _connection.CreateCommand();
- _deleteAllCommand.CommandText = "delete from FileOrganizerResults";
+ connection.RunQueries(queries, Logger);
+ }
}
public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
@@ -95,65 +50,84 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- _saveResultCommand.GetParameter(index++).Value = new Guid(result.Id);
- _saveResultCommand.GetParameter(index++).Value = result.OriginalPath;
- _saveResultCommand.GetParameter(index++).Value = result.TargetPath;
- _saveResultCommand.GetParameter(index++).Value = result.FileSize;
- _saveResultCommand.GetParameter(index++).Value = result.Date;
- _saveResultCommand.GetParameter(index++).Value = result.Status.ToString();
- _saveResultCommand.GetParameter(index++).Value = result.Type.ToString();
- _saveResultCommand.GetParameter(index++).Value = result.StatusMessage;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedName;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedYear;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber;
- _saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber;
- _saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray());
-
- _saveResultCommand.Transaction = transaction;
-
- _saveResultCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- if (transaction != null)
+ using (var saveResultCommand = connection.CreateCommand())
{
- transaction.Rollback();
- }
+ saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
+
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ResultId");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OriginalPath");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@TargetPath");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@FileLength");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationDate");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@Status");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationType");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@StatusMessage");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedName");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedYear");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedSeasonNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEpisodeNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEndingEpisodeNumber");
+ saveResultCommand.Parameters.Add(saveResultCommand, "@DuplicatePaths");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ saveResultCommand.GetParameter(index++).Value = new Guid(result.Id);
+ saveResultCommand.GetParameter(index++).Value = result.OriginalPath;
+ saveResultCommand.GetParameter(index++).Value = result.TargetPath;
+ saveResultCommand.GetParameter(index++).Value = result.FileSize;
+ saveResultCommand.GetParameter(index++).Value = result.Date;
+ saveResultCommand.GetParameter(index++).Value = result.Status.ToString();
+ saveResultCommand.GetParameter(index++).Value = result.Type.ToString();
+ saveResultCommand.GetParameter(index++).Value = result.StatusMessage;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedName;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedYear;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber;
+ saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber;
+ saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray());
+
+ saveResultCommand.Transaction = transaction;
+
+ saveResultCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save FileOrganizationResult:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save FileOrganizationResult:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -164,100 +138,110 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("id");
}
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var deleteResultCommand = connection.CreateCommand())
+ {
+ deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId";
- IDbTransaction transaction = null;
+ deleteResultCommand.Parameters.Add(deleteResultCommand, "@ResultId");
- try
- {
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- _deleteResultCommand.GetParameter(0).Value = new Guid(id);
+ try
+ {
+ transaction = connection.BeginTransaction();
- _deleteResultCommand.Transaction = transaction;
+ deleteResultCommand.GetParameter(0).Value = new Guid(id);
- _deleteResultCommand.ExecuteNonQuery();
+ deleteResultCommand.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ deleteResultCommand.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
public async Task DeleteAll()
{
- await WriteLock.WaitAsync().ConfigureAwait(false);
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "delete from FileOrganizerResults";
- IDbTransaction transaction = null;
+ IDbTransaction transaction = null;
- try
- {
- transaction = _connection.BeginTransaction();
-
- _deleteAllCommand.Transaction = transaction;
+ try
+ {
+ transaction = connection.BeginTransaction();
- _deleteAllCommand.ExecuteNonQuery();
+ cmd.Transaction = transaction;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ cmd.ExecuteNonQuery();
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete results", e);
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete results", e);
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- WriteLock.Release();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
}
-
+
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
{
if (query == null)
@@ -265,46 +249,49 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
-
- if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
+ using (var cmd = connection.CreateCommand())
{
- cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
- query.StartIndex.Value.ToString(_usCulture));
- }
+ cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
- cmd.CommandText += " ORDER BY OrganizationDate desc";
+ if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
+ {
+ cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
+ query.StartIndex.Value.ToString(_usCulture));
+ }
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ cmd.CommandText += " ORDER BY OrganizationDate desc";
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (ResultId) from FileOrganizerResults";
+ cmd.CommandText += "; select count (ResultId) from FileOrganizerResults";
- var list = new List<FileOrganizationResult>();
- var count = 0;
+ var list = new List<FileOrganizationResult>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(GetResult(reader));
+ while (reader.Read())
+ {
+ list.Add(GetResult(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<FileOrganizationResult>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<FileOrganizationResult>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -315,24 +302,27 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("id");
}
- var guid = new Guid(id);
-
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id";
+ var guid = new Guid(id);
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var cmd = connection.CreateCommand())
{
- if (reader.Read())
+ cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetResult(reader);
+ if (reader.Read())
+ {
+ return GetResult(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
public FileOrganizationResult GetResult(IDataReader reader)
@@ -414,19 +404,5 @@ namespace MediaBrowser.Server.Implementations.Persistence
return result;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 460a67ca7..6d067e345 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -22,6 +22,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Server.Implementations.Persistence
@@ -94,13 +95,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _updateInheritedRatingCommand;
private IDbCommand _updateInheritedTagsCommand;
- public const int LatestSchemaVersion = 89;
+ public const int LatestSchemaVersion = 96;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
/// </summary>
- public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager)
- : base(logManager)
+ public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager, IDbConnector connector)
+ : base(logManager, connector)
{
if (config == null)
{
@@ -115,61 +116,72 @@ namespace MediaBrowser.Server.Implementations.Persistence
_jsonSerializer = jsonSerializer;
_criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews");
+ DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
}
private const string ChaptersTableName = "Chapters2";
+ protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, false, 10000).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory",
+ "pragma default_temp_store = memory",
+ "PRAGMA locking_mode=EXCLUSIVE"
+
+ }, Logger);
+
+ return connection;
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize(SqliteUserDataRepository userDataRepo)
{
- var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
+ _connection = await CreateConnection(false).ConfigureAwait(false);
var createMediaStreamsTableCommand
- = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
+ = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
string[] queries = {
"create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)",
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
- "create index if not exists idx_TypedBaseItems2 on TypedBaseItems(Type,Guid)",
"create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))",
"create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)",
"create index if not exists idx_AncestorIds2 on AncestorIds(AncestorIdText)",
- "create table if not exists UserDataKeys (ItemId GUID, UserDataKey TEXT, PRIMARY KEY (ItemId, UserDataKey))",
- "create index if not exists idx_UserDataKeys1 on UserDataKeys(ItemId)",
+ "create table if not exists UserDataKeys (ItemId GUID, UserDataKey TEXT Priority INT, PRIMARY KEY (ItemId, UserDataKey))",
- "create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT)",
- "create index if not exists idx_ItemValues on ItemValues(ItemId)",
+ "create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT, CleanValue TEXT)",
+ //"create index if not exists idx_ItemValues on ItemValues(ItemId)",
"create index if not exists idx_ItemValues2 on ItemValues(ItemId,Type)",
"create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT, PRIMARY KEY (ItemId, Name))",
- "create index if not exists Idx_ProviderIds on ProviderIds(ItemId)",
+ // covering index
+ "create index if not exists Idx_ProviderIds1 on ProviderIds(ItemId,Name,Value)",
"create table if not exists Images (ItemId GUID NOT NULL, Path TEXT NOT NULL, ImageType INT NOT NULL, DateModified DATETIME, IsPlaceHolder BIT NOT NULL, SortOrder INT)",
"create index if not exists idx_Images on Images(ItemId)",
"create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
- "create index if not exists idxPeopleItemId on People(ItemId)",
+
+ "drop index if exists idxPeopleItemId",
+ "create index if not exists idxPeopleItemId1 on People(ItemId,ListOrder)",
"create index if not exists idxPeopleName on People(Name)",
"create table if not exists "+ChaptersTableName+" (ItemId GUID, ChapterIndex INT, StartPositionTicks BIGINT, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))",
- "create index if not exists idx_"+ChaptersTableName+"1 on "+ChaptersTableName+"(ItemId)",
createMediaStreamsTableCommand,
- "create index if not exists idx_mediastreams1 on mediastreams(ItemId)",
- //pragmas
- "pragma temp_store = memory",
+ "create index if not exists idx_mediastreams1 on mediastreams(ItemId)",
- "pragma shrink_memory"
};
_connection.RunQueries(queries, Logger);
@@ -254,16 +266,60 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT");
_connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "UserDataKey", "Text");
_connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
+ _connection.AddColumn(Logger, "ItemValues", "CleanValue", "Text");
string[] postQueries =
- {
+
+ {
+ // obsolete
+ "drop index if exists idx_TypedBaseItems",
+ "drop index if exists idx_mediastreams",
+ "drop index if exists idx_"+ChaptersTableName,
+ "drop index if exists idx_UserDataKeys1",
+ "drop index if exists idx_UserDataKeys2",
+ "drop index if exists idx_TypeTopParentId3",
+ "drop index if exists idx_TypeTopParentId2",
+ "drop index if exists idx_TypeTopParentId4",
+ "drop index if exists idx_Type",
+ "drop index if exists idx_TypeTopParentId",
+ "drop index if exists idx_GuidType",
+ "drop index if exists idx_TopParentId",
+ "drop index if exists idx_TypeTopParentId6",
+ "drop index if exists idx_ItemValues2",
+ "drop index if exists Idx_ProviderIds",
+
"create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)",
- "create index if not exists idx_Type on TypedBaseItems(Type)",
- "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)",
- "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)"
- };
+ "create index if not exists idx_GuidTypeIsFolderIsVirtualItem on TypedBaseItems(Guid,Type,IsFolder,IsVirtualItem)",
+ //"create index if not exists idx_GuidMediaTypeIsFolderIsVirtualItem on TypedBaseItems(Guid,MediaType,IsFolder,IsVirtualItem)",
+ "create index if not exists idx_CleanNameType on TypedBaseItems(CleanName,Type)",
+
+ // covering index
+ "create index if not exists idx_TopParentIdGuid on TypedBaseItems(TopParentId,Guid)",
+
+ // live tv programs
+ "create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)",
+
+ // used by movie suggestions
+ "create index if not exists idx_TypeTopParentIdGroup on TypedBaseItems(Type,TopParentId,PresentationUniqueKey)",
+ "create index if not exists idx_TypeTopParentId5 on TypedBaseItems(TopParentId,IsVirtualItem)",
+
+ // latest items
+ "create index if not exists idx_TypeTopParentId9 on TypedBaseItems(TopParentId,Type,IsVirtualItem,PresentationUniqueKey,DateCreated)",
+ "create index if not exists idx_TypeTopParentId8 on TypedBaseItems(TopParentId,IsFolder,IsVirtualItem,PresentationUniqueKey,DateCreated)",
+
+ // resume
+ "create index if not exists idx_TypeTopParentId7 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem,PresentationUniqueKey)",
+
+ // items by name
+ "create index if not exists idx_ItemValues3 on ItemValues(ItemId,Type,CleanValue)",
+ "create index if not exists idx_ItemValues4 on ItemValues(ItemId,Type,Value,CleanValue)",
+
+ // covering index
+ "create index if not exists idx_UserDataKeys3 on UserDataKeys(ItemId,Priority,UserDataKey)"
+ };
_connection.RunQueries(postQueries, Logger);
@@ -272,6 +328,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
new MediaStreamColumns(_connection, Logger).AddColumns();
DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb");
+ await userDataRepo.Initialize(_connection).ConfigureAwait(false);
+ //await Vacuum(_connection).ConfigureAwait(false);
}
private readonly string[] _retriveItemColumns =
@@ -368,7 +426,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
"Comment",
"NalLengthSize",
"IsAvc",
- "Title"
+ "Title",
+ "TimeBase",
+ "CodecTimeBase"
};
/// <summary>
@@ -451,7 +511,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"DateLastMediaAdded",
"Album",
"IsVirtualItem",
- "SeriesName"
+ "SeriesName",
+ "UserDataKey"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -554,10 +615,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteItemValuesCommand.Parameters.Add(_deleteItemValuesCommand, "@Id");
_saveItemValuesCommand = _connection.CreateCommand();
- _saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)";
+ _saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)";
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@ItemId");
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Type");
_saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Value");
+ _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@CleanValue");
// provider ids
_deleteProviderIdsCommand = _connection.CreateCommand();
@@ -867,15 +929,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.Album;
- var season = item as Season;
- if (season != null && season.IsVirtualItem.HasValue)
- {
- _saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value;
- }
- else
- {
- _saveItemCommand.GetParameter(index++).Value = null;
- }
+ _saveItemCommand.GetParameter(index++).Value = item.IsVirtualItem || (!item.IsFolder && item.LocationType == LocationType.Virtual);
var hasSeries = item as IHasSeries;
if (hasSeries != null)
@@ -887,6 +941,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = null;
}
+ _saveItemCommand.GetParameter(index++).Value = item.GetUserDataKeys().FirstOrDefault();
+
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@@ -899,7 +955,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction);
UpdateImages(item.Id, item.ImageInfos, transaction);
UpdateProviderIds(item.Id, item.ProviderIds, transaction);
- UpdateItemValues(item.Id, GetItemValues(item), transaction);
+ UpdateItemValues(item.Id, GetItemValuesToSave(item), transaction);
}
transaction.Commit();
@@ -1304,10 +1360,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.CriticRatingSummary = reader.GetString(57);
}
- var season = item as Season;
- if (season != null && !reader.IsDBNull(58))
+ if (!reader.IsDBNull(58))
{
- season.IsVirtualItem = reader.GetBoolean(58);
+ item.IsVirtualItem = reader.GetBoolean(58);
}
return item;
@@ -1459,7 +1514,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// or
/// cancellationToken
/// </exception>
- public async Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public async Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1686,10 +1741,42 @@ namespace MediaBrowser.Server.Implementations.Persistence
return string.Empty;
}
- return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key";
+ if (_config.Configuration.SchemaVersion >= 96)
+ {
+ return " left join UserDataDb.UserData on UserDataKey=UserDataDb.UserData.Key And (UserId=@UserId)";
+ }
+
+ return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key And (UserId=@UserId)";
+ }
+
+ private string GetGroupBy(InternalItemsQuery query)
+ {
+ var groups = new List<string>();
+
+ if (!string.IsNullOrWhiteSpace(query.GroupByAncestorOfType))
+ {
+ groups.Add("(Select PresentationUniqueKey from TypedBaseItems B where B.Type = 'MediaBrowser.Controller.Entities.TV.Series' And B.Guid in (Select AncestorId from AncestorIds where ItemId=A.Guid))");
+ }
+
+ if (EnableGroupByPresentationUniqueKey(query))
+ {
+ groups.Add("PresentationUniqueKey");
+ }
+
+ if (groups.Count > 0)
+ {
+ return " Group by " + string.Join(",", groups.ToArray());
+ }
+
+ return string.Empty;
}
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
+ private string GetFromText()
+ {
+ return " from TypedBaseItems A";
+ }
+
+ public List<BaseItem> GetItemList(InternalItemsQuery query)
{
if (query == null)
{
@@ -1700,9 +1787,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
var now = DateTime.UtcNow;
+ var list = new List<BaseItem>();
+
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -1718,22 +1807,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- var limit = query.Limit ?? int.MaxValue;
+ var offset = query.StartIndex ?? 0;
- cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.StartIndex.HasValue)
+ if (offset > 0)
{
- cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
@@ -1746,11 +1835,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
var item = GetItem(reader);
if (item != null)
{
- yield return item;
+ list.Add(item);
}
}
}
}
+
+ return list;
}
private void LogQueryTime(string methodName, IDbCommand cmd, DateTime startDate)
@@ -1760,7 +1851,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
var slowThreshold = 1000;
#if DEBUG
- slowThreshold = 100;
+ slowThreshold = 50;
#endif
if (elapsed >= slowThreshold)
@@ -1788,11 +1879,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
+ {
+ var list = GetItemList(query);
+ return new QueryResult<BaseItem>
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = list.Count
+ };
+ }
+
var now = DateTime.UtcNow;
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -1812,32 +1913,41 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- var limit = query.Limit ?? int.MaxValue;
+ var offset = query.StartIndex ?? 0;
- cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.StartIndex.HasValue)
+ if (offset > 0)
{
- cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
+ cmd.CommandText += ";";
+
+ var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
+
+ if (isReturningZeroItems)
+ {
+ cmd.CommandText = "";
+ }
+
if (EnableGroupByPresentationUniqueKey(query))
{
- cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ cmd.CommandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
}
else
{
- cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ cmd.CommandText += " select count (guid)" + GetFromText();
}
cmd.CommandText += GetJoinUserDataText(query);
@@ -1850,18 +1960,28 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
LogQueryTime("GetItems", cmd, now);
- while (reader.Read())
+ if (isReturningZeroItems)
{
- var item = GetItem(reader);
- if (item != null)
+ if (reader.Read())
{
- list.Add(item);
+ count = reader.GetInt32(0);
}
}
-
- if (reader.NextResult() && reader.Read())
+ else
{
- count = reader.GetInt32(0);
+ while (reader.Read())
+ {
+ var item = GetItem(reader);
+ if (item != null)
+ {
+ list.Add(item);
+ }
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
}
@@ -1881,11 +2001,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
if (query.User != null)
{
- query.SortBy = new[] { "SimilarityScore", "IsPlayed", "Random" };
+ query.SortBy = new[] { "SimilarityScore", ItemSortBy.IsPlayed, ItemSortBy.Random };
}
else
{
- query.SortBy = new[] { "SimilarityScore", "Random" };
+ query.SortBy = new[] { "SimilarityScore", ItemSortBy.Random };
}
query.SortOrder = SortOrder.Descending;
}
@@ -1900,7 +2020,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return " ORDER BY " + string.Join(",", query.SortBy.Select(i =>
{
- var columnMap = MapOrderByField(i);
+ var columnMap = MapOrderByField(i, query);
var columnAscending = isAscending;
if (columnMap.Item2)
{
@@ -1913,7 +2033,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}).ToArray());
}
- private Tuple<string, bool> MapOrderByField(string name)
+ private Tuple<string, bool> MapOrderByField(string name, InternalItemsQuery query)
{
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
{
@@ -1972,6 +2092,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return new Tuple<string, bool>("(select value from itemvalues where ItemId=Guid and Type=3 LIMIT 1)", false);
}
+ if (string.Equals(name, ItemSortBy.SeriesDatePlayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where B.Guid in (Select ItemId from AncestorIds where AncestorId in (select guid from typedbaseitems c where C.Type = 'MediaBrowser.Controller.Entities.TV.Series' And C.Guid in (Select AncestorId from AncestorIds where ItemId=A.Guid))))", false);
+ }
return new Tuple<string, bool>(name, false);
}
@@ -1989,7 +2113,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + GetFromText();
cmd.CommandText += GetJoinUserDataText(query);
if (EnableJoinUserData(query))
@@ -2005,22 +2129,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- var limit = query.Limit ?? int.MaxValue;
+ var offset = query.StartIndex ?? 0;
- cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.StartIndex.HasValue)
+ if (offset > 0)
{
- cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
@@ -2065,22 +2189,22 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- var limit = query.Limit ?? int.MaxValue;
+ var offset = query.StartIndex ?? 0;
- cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.StartIndex.HasValue)
+ if (offset > 0)
{
- cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
@@ -2128,11 +2252,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
+ {
+ var list = GetItemIdsList(query);
+ return new QueryResult<Guid>
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = list.Count
+ };
+ }
+
var now = DateTime.UtcNow;
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + GetFromText();
var whereClauses = GetWhereClauses(query, cmd);
cmd.CommandText += GetJoinUserDataText(query);
@@ -2148,32 +2282,32 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- cmd.CommandText += " Group by PresentationUniqueKey";
- }
+ cmd.CommandText += GetGroupBy(query);
cmd.CommandText += GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- var limit = query.Limit ?? int.MaxValue;
+ var offset = query.StartIndex ?? 0;
- cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
- if (query.StartIndex.HasValue)
+ if (offset > 0)
{
- cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
if (EnableGroupByPresentationUniqueKey(query))
{
- cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ cmd.CommandText += "; select count (distinct PresentationUniqueKey)" + GetFromText();
}
else
{
- cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ cmd.CommandText += "; select count (guid)" + GetFromText();
}
cmd.CommandText += GetJoinUserDataText(query);
@@ -2205,13 +2339,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- private List<string> GetWhereClauses(InternalItemsQuery query, IDbCommand cmd)
+ private List<string> GetWhereClauses(InternalItemsQuery query, IDbCommand cmd, string paramSuffix = "")
{
var whereClauses = new List<string>();
if (EnableJoinUserData(query))
{
- whereClauses.Add("(UserId is null or UserId=@UserId)");
+ //whereClauses.Add("(UserId is null or UserId=@UserId)");
}
if (query.IsCurrentSchema.HasValue)
{
@@ -2281,8 +2415,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
if (includeTypes.Length == 1)
{
- whereClauses.Add("type=@type");
- cmd.Parameters.Add(cmd, "@type", DbType.String).Value = includeTypes[0];
+ whereClauses.Add("type=@type" + paramSuffix);
+ cmd.Parameters.Add(cmd, "@type" + paramSuffix, DbType.String).Value = includeTypes[0];
}
else if (includeTypes.Length > 1)
{
@@ -2365,6 +2499,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
cmd.Parameters.Add(cmd, "@ParentIndexNumber", DbType.Int32).Value = query.ParentIndexNumber.Value;
}
+ if (query.ParentIndexNumberNotEquals.HasValue)
+ {
+ whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)");
+ cmd.Parameters.Add(cmd, "@ParentIndexNumberNotEquals", DbType.Int32).Value = query.ParentIndexNumberNotEquals.Value;
+ }
if (query.MinEndDate.HasValue)
{
whereClauses.Add("EndDate>=@MinEndDate");
@@ -2581,8 +2720,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var artist in query.ArtistNames)
{
- clauses.Add("@ArtistName" + index + " in (select value from itemvalues where ItemId=Guid and Type <= 1)");
- cmd.Parameters.Add(cmd, "@ArtistName" + index, DbType.String).Value = artist;
+ clauses.Add("@ArtistName" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type <= 1)");
+ cmd.Parameters.Add(cmd, "@ArtistName" + index, DbType.String).Value = artist.RemoveDiacritics();
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2595,8 +2734,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Genres)
{
- clauses.Add("@Genre" + index + " in (select value from itemvalues where ItemId=Guid and Type=2)");
- cmd.Parameters.Add(cmd, "@Genre" + index, DbType.String).Value = item;
+ clauses.Add("@Genre" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
+ cmd.Parameters.Add(cmd, "@Genre" + index, DbType.String).Value = item.RemoveDiacritics();
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2609,8 +2748,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Tags)
{
- clauses.Add("@Tag" + index + " in (select value from itemvalues where ItemId=Guid and Type=4)");
- cmd.Parameters.Add(cmd, "@Tag" + index, DbType.String).Value = item;
+ clauses.Add("@Tag" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=4)");
+ cmd.Parameters.Add(cmd, "@Tag" + index, DbType.String).Value = item.RemoveDiacritics();
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2623,8 +2762,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Studios)
{
- clauses.Add("@Studio" + index + " in (select value from itemvalues where ItemId=Guid and Type=3)");
- cmd.Parameters.Add(cmd, "@Studio" + index, DbType.String).Value = item;
+ clauses.Add("@Studio" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=3)");
+ cmd.Parameters.Add(cmd, "@Studio" + index, DbType.String).Value = item.RemoveDiacritics();
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2637,8 +2776,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var item in query.Keywords)
{
- clauses.Add("@Keyword" + index + " in (select value from itemvalues where ItemId=Guid and Type=5)");
- cmd.Parameters.Add(cmd, "@Keyword" + index, DbType.String).Value = item;
+ clauses.Add("@Keyword" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=5)");
+ cmd.Parameters.Add(cmd, "@Keyword" + index, DbType.String).Value = item.RemoveDiacritics();
index++;
}
var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2717,8 +2856,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (query.LocationTypes.Length == 1)
{
- whereClauses.Add("LocationType=@LocationType");
- cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString();
+ if (query.LocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90)
+ {
+ query.IsVirtualItem = true;
+ }
+ else
+ {
+ whereClauses.Add("LocationType=@LocationType");
+ cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString();
+ }
}
else if (query.LocationTypes.Length > 1)
{
@@ -2728,8 +2874,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
if (query.ExcludeLocationTypes.Length == 1)
{
- whereClauses.Add("LocationType<>@ExcludeLocationTypes");
- cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString();
+ if (query.ExcludeLocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90)
+ {
+ query.IsVirtualItem = false;
+ }
+ else
+ {
+ whereClauses.Add("LocationType<>@ExcludeLocationTypes");
+ cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString();
+ }
}
else if (query.ExcludeLocationTypes.Length > 1)
{
@@ -2737,6 +2890,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("LocationType not in (" + val + ")");
}
+ if (query.IsVirtualItem.HasValue)
+ {
+ whereClauses.Add("IsVirtualItem=@IsVirtualItem");
+ cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value;
+ }
if (query.MediaTypes.Length == 1)
{
whereClauses.Add("MediaType=@MediaTypes");
@@ -2748,6 +2906,20 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("MediaType in (" + val + ")");
}
+ if (query.ItemIds.Length > 0)
+ {
+ var excludeIds = new List<string>();
+
+ var index = 0;
+ foreach (var id in query.ItemIds)
+ {
+ excludeIds.Add("Guid = @IncludeId" + index);
+ cmd.Parameters.Add(cmd, "@IncludeId" + index, DbType.Guid).Value = new Guid(id);
+ index++;
+ }
+
+ whereClauses.Add(string.Join(" OR ", excludeIds.ToArray()));
+ }
if (query.ExcludeItemIds.Length > 0)
{
var excludeIds = new List<string>();
@@ -3414,7 +3586,294 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- private List<Tuple<int, string>> GetItemValues(BaseItem item)
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 0, typeof(MusicArtist).FullName);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 1, typeof(MusicArtist).FullName);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 3, typeof(Studio).FullName);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 2, typeof(Genre).FullName);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 2, typeof(GameGenre).FullName);
+ }
+
+ public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
+ {
+ return GetItemValues(query, 2, typeof(MusicGenre).FullName);
+ }
+
+ private QueryResult<Tuple<BaseItem, ItemCounts>> GetItemValues(InternalItemsQuery query, int itemValueType, string returnType)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ if (!query.Limit.HasValue)
+ {
+ query.EnableTotalRecordCount = false;
+ }
+
+ CheckDisposed();
+
+ var now = DateTime.UtcNow;
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ var itemCountColumns = new List<Tuple<string, string>>();
+
+ var typesToCount = query.IncludeItemTypes.ToList();
+
+ if (typesToCount.Count == 0)
+ {
+ //typesToCount.Add("Item");
+ }
+
+ foreach (var type in typesToCount)
+ {
+ var itemCountColumnQuery = "Select Count(Value) from ItemValues where ItemValues.CleanValue=CleanName AND Type=@ItemValueType AND ItemId in (";
+ itemCountColumnQuery += "select guid" + GetFromText();
+
+ var typeSubQuery = new InternalItemsQuery(query.User)
+ {
+ ExcludeItemTypes = query.ExcludeItemTypes,
+ MediaTypes = query.MediaTypes,
+ AncestorIds = query.AncestorIds,
+ ExcludeItemIds = query.ExcludeItemIds,
+ ItemIds = query.ItemIds,
+ TopParentIds = query.TopParentIds,
+ ParentId = query.ParentId,
+ IsPlayed = query.IsPlayed
+ };
+ if (string.Equals(type, "Item", StringComparison.OrdinalIgnoreCase))
+ {
+ typeSubQuery.IncludeItemTypes = query.IncludeItemTypes;
+ }
+ else
+ {
+ typeSubQuery.IncludeItemTypes = new[] { type };
+ }
+ var whereClauses = GetWhereClauses(typeSubQuery, cmd, type);
+
+ var typeWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ itemCountColumnQuery += typeWhereText;
+
+ itemCountColumnQuery += ")";
+
+ var columnName = type + "Count";
+
+ itemCountColumns.Add(new Tuple<string, string>(columnName, "(" + itemCountColumnQuery + ") as " + columnName));
+ }
+
+ var columns = _retriveItemColumns.ToList();
+ columns.AddRange(itemCountColumns.Select(i => i.Item2).ToArray());
+
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, columns.ToArray(), cmd)) + GetFromText();
+ cmd.CommandText += GetJoinUserDataText(query);
+
+ var innerQuery = new InternalItemsQuery(query.User)
+ {
+ ExcludeItemTypes = query.ExcludeItemTypes,
+ IncludeItemTypes = query.IncludeItemTypes,
+ MediaTypes = query.MediaTypes,
+ AncestorIds = query.AncestorIds,
+ ExcludeItemIds = query.ExcludeItemIds,
+ ItemIds = query.ItemIds,
+ TopParentIds = query.TopParentIds,
+ ParentId = query.ParentId,
+ IsPlayed = query.IsPlayed
+ };
+
+ var innerWhereClauses = GetWhereClauses(innerQuery, cmd);
+
+ var innerWhereText = innerWhereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", innerWhereClauses.ToArray());
+
+ var whereText = " where Type=@SelectType";
+ whereText += " And CleanName In (Select CleanValue from ItemValues where Type=@ItemValueType AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
+
+ var outerQuery = new InternalItemsQuery(query.User)
+ {
+ IsFavorite = query.IsFavorite,
+ IsFavoriteOrLiked = query.IsFavoriteOrLiked,
+ IsLiked = query.IsLiked,
+ IsLocked = query.IsLocked,
+ NameLessThan = query.NameLessThan,
+ NameStartsWith = query.NameStartsWith,
+ NameStartsWithOrGreater = query.NameStartsWithOrGreater,
+ AlbumArtistStartsWithOrGreater = query.AlbumArtistStartsWithOrGreater,
+ Tags = query.Tags,
+ OfficialRatings = query.OfficialRatings,
+ Genres = query.GenreIds,
+ Years = query.Years
+ };
+
+ var outerWhereClauses = GetWhereClauses(outerQuery, cmd);
+
+ whereText += outerWhereClauses.Count == 0 ?
+ string.Empty :
+ " AND " + string.Join(" AND ", outerWhereClauses.ToArray());
+ //cmd.CommandText += GetGroupBy(query);
+
+ cmd.CommandText += whereText;
+ cmd.CommandText += " group by PresentationUniqueKey";
+
+ cmd.Parameters.Add(cmd, "@SelectType", DbType.String).Value = returnType;
+ cmd.Parameters.Add(cmd, "@ItemValueType", DbType.Int32).Value = itemValueType;
+
+ if (EnableJoinUserData(query))
+ {
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id;
+ }
+
+ cmd.CommandText += " order by SortName";
+
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
+ {
+ var offset = query.StartIndex ?? 0;
+
+ if (query.Limit.HasValue || offset > 0)
+ {
+ cmd.CommandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (offset > 0)
+ {
+ cmd.CommandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
+ }
+ }
+
+ cmd.CommandText += ";";
+
+ var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
+
+ if (isReturningZeroItems)
+ {
+ cmd.CommandText = "";
+ }
+
+ if (query.EnableTotalRecordCount)
+ {
+ cmd.CommandText += "select count (distinct PresentationUniqueKey)" + GetFromText();
+
+ cmd.CommandText += GetJoinUserDataText(query);
+ cmd.CommandText += whereText;
+ }
+ else
+ {
+ cmd.CommandText = cmd.CommandText.TrimEnd(';');
+ }
+
+ var list = new List<Tuple<BaseItem, ItemCounts>>();
+ var count = 0;
+
+ var commandBehavior = isReturningZeroItems || !query.EnableTotalRecordCount
+ ? (CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)
+ : CommandBehavior.SequentialAccess;
+
+ using (var reader = cmd.ExecuteReader(commandBehavior))
+ {
+ LogQueryTime("GetItemValues", cmd, now);
+
+ if (isReturningZeroItems)
+ {
+ if (reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+ else
+ {
+ while (reader.Read())
+ {
+ var item = GetItem(reader);
+ if (item != null)
+ {
+ var countStartColumn = columns.Count - typesToCount.Count;
+
+ list.Add(new Tuple<BaseItem, ItemCounts>(item, GetItemCounts(reader, countStartColumn, typesToCount)));
+ }
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ count = list.Count;
+ }
+
+ return new QueryResult<Tuple<BaseItem, ItemCounts>>
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+
+ }
+ }
+
+ private ItemCounts GetItemCounts(IDataReader reader, int countStartColumn, List<string> typesToCount)
+ {
+ var counts = new ItemCounts();
+
+ for (var i = 0; i < typesToCount.Count; i++)
+ {
+ var value = reader.GetInt32(countStartColumn + i);
+
+ var type = typesToCount[i];
+ if (string.Equals(type, "Series", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.SeriesCount = value;
+ }
+ else if (string.Equals(type, "Episode", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.EpisodeCount = value;
+ }
+ else if (string.Equals(type, "Movie", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.MovieCount = value;
+ }
+ else if (string.Equals(type, "MusicAlbum", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.AlbumCount = value;
+ }
+ else if (string.Equals(type, "Audio", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.SongCount = value;
+ }
+ else if (string.Equals(type, "Game", StringComparison.OrdinalIgnoreCase))
+ {
+ counts.GameCount = value;
+ }
+ counts.ItemCount += value;
+ }
+
+ return counts;
+ }
+
+ private List<Tuple<int, string>> GetItemValuesToSave(BaseItem item)
{
var list = new List<Tuple<int, string>>();
@@ -3540,6 +3999,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemValuesCommand.GetParameter(0).Value = itemId;
_saveItemValuesCommand.GetParameter(1).Value = pair.Item1;
_saveItemValuesCommand.GetParameter(2).Value = pair.Item2;
+ if (pair.Item2 == null)
+ {
+ _saveItemValuesCommand.GetParameter(3).Value = null;
+ }
+ else
+ {
+ _saveItemValuesCommand.GetParameter(3).Value = pair.Item2.RemoveDiacritics();
+ }
_saveItemValuesCommand.Transaction = transaction;
_saveItemValuesCommand.ExecuteNonQuery();
@@ -3732,7 +4199,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return list;
}
- public async Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
+ public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -3805,6 +4272,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStreamCommand.GetParameter(index++).Value = stream.IsAVC;
_saveStreamCommand.GetParameter(index++).Value = stream.Title;
+ _saveStreamCommand.GetParameter(index++).Value = stream.TimeBase;
+ _saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase;
+
_saveStreamCommand.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery();
}
@@ -3977,6 +4447,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.Title = reader.GetString(29);
}
+ if (!reader.IsDBNull(30))
+ {
+ item.TimeBase = reader.GetString(30);
+ }
+
+ if (!reader.IsDBNull(31))
+ {
+ item.CodecTimeBase = reader.GetString(31);
+ }
+
return item;
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
index bfdb9e0c7..90dbd7770 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
@@ -16,11 +16,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
{
private IDbConnection _connection;
- private readonly IApplicationPaths _appPaths;
- public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
+ public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "userdata_v2.db");
+ }
+
+ protected override bool EnableConnectionPooling
+ {
+ get { return false; }
}
/// <summary>
@@ -35,22 +39,38 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
+ {
+ var connection = await DbConnector.Connect(DbFilePath, false, false, 10000).ConfigureAwait(false);
+
+ connection.RunQueries(new[]
+ {
+ "pragma temp_store = memory"
+
+ }, Logger);
+
+ return connection;
+ }
+
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize(IDbConnection connection)
{
- var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
+ _connection = connection;
string[] queries = {
- "create table if not exists userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)",
+ "create table if not exists UserDataDb.userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)",
+
+ "drop index if exists UserDataDb.idx_userdata",
+ "drop index if exists UserDataDb.idx_userdata1",
+ "drop index if exists UserDataDb.idx_userdata2",
+ "drop index if exists UserDataDb.userdataindex1",
- "create index if not exists idx_userdata on userdata(key)",
- "create unique index if not exists userdataindex on userdata (key, userId)",
+ "create unique index if not exists UserDataDb.userdataindex on userdata (key, userId)",
+ "create index if not exists UserDataDb.userdataindex2 on userdata (key, userId, played)",
//pragmas
"pragma temp_store = memory",
@@ -316,18 +336,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
var index = 0;
- var excludeIds = new List<string>();
+ var userdataKeys = new List<string>();
var builder = new StringBuilder();
foreach (var key in keys)
{
var paramName = "@Key" + index;
- excludeIds.Add("Key =" + paramName);
+ userdataKeys.Add("Key =" + paramName);
cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key;
builder.Append(" WHEN Key=" + paramName + " THEN " + index);
index++;
+ break;
}
- var keyText = string.Join(" OR ", excludeIds.ToArray());
+ var keyText = string.Join(" OR ", userdataKeys.ToArray());
cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") ";
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
index f7ca39a54..25ab60ca5 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
@@ -17,14 +17,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
{
- private IDbConnection _connection;
- private readonly IServerApplicationPaths _appPaths;
private readonly IJsonSerializer _jsonSerializer;
- public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager)
+ public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector) : base(logManager, dbConnector)
{
- _appPaths = appPaths;
_jsonSerializer = jsonSerializer;
+
+ DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
}
/// <summary>
@@ -43,25 +42,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists users (guid GUID primary key, data BLOB)",
"create index if not exists idx_users on users(guid)",
"create table if not exists schema_version (table_name primary key, version)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
+ }
}
/// <summary>
@@ -84,55 +79,54 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
- cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id;
- cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized;
+ transaction = connection.BeginTransaction();
+
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
+ cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id;
+ cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized;
- cmd.Transaction = transaction;
+ cmd.Transaction = transaction;
- cmd.ExecuteNonQuery();
- }
+ cmd.ExecuteNonQuery();
+ }
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
{
- transaction.Rollback();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save user:", e);
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save user:", e);
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ throw;
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ finally
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- WriteLock.Release();
}
}
@@ -142,25 +136,32 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <returns>IEnumerable{User}.</returns>
public IEnumerable<User> RetrieveAllUsers()
{
- using (var cmd = _connection.CreateCommand())
- {
- cmd.CommandText = "select guid,data from users";
+ var list = new List<User>();
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ using (var connection = CreateConnection(true).Result)
+ {
+ using (var cmd = connection.CreateCommand())
{
- while (reader.Read())
- {
- var id = reader.GetGuid(0);
+ cmd.CommandText = "select guid,data from users";
- using (var stream = reader.GetMemoryStream(1))
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
{
- var user = _jsonSerializer.DeserializeFromStream<User>(stream);
- user.Id = id;
- yield return user;
+ var id = reader.GetGuid(0);
+
+ using (var stream = reader.GetMemoryStream(1))
+ {
+ var user = _jsonSerializer.DeserializeFromStream<User>(stream);
+ user.Id = id;
+ list.Add(user);
+ }
}
}
}
}
+
+ return list;
}
/// <summary>
@@ -179,69 +180,54 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ IDbTransaction transaction = null;
- using (var cmd = _connection.CreateCommand())
+ try
{
- cmd.CommandText = "delete from users where guid=@guid";
+ transaction = connection.BeginTransaction();
- cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = "delete from users where guid=@guid";
- cmd.ExecuteNonQuery();
- }
+ cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ cmd.Transaction = transaction;
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to delete user:", e);
+ cmd.ExecuteNonQuery();
+ }
- if (transaction != null)
- {
- transaction.Rollback();
+ transaction.Commit();
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
+ catch (OperationCanceledException)
{
- transaction.Dispose();
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
}
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to delete user:", e);
- WriteLock.Release();
- }
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
+ throw;
+ }
+ finally
{
- _connection.Close();
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
}
-
- _connection.Dispose();
- _connection = null;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
index e8d9814ec..74a552dcc 100644
--- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
@@ -15,57 +15,30 @@ namespace MediaBrowser.Server.Implementations.Security
{
public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository
{
- private IDbConnection _connection;
private readonly IServerApplicationPaths _appPaths;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _saveInfoCommand;
-
- public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths)
- : base(logManager)
+ public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
_appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "authentication.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
- "create index if not exists idx_AccessTokens on AccessTokens(Id)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
+ "create index if not exists idx_AccessTokens on AccessTokens(Id)"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
- _connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT");
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- _saveInfoCommand = _connection.CreateCommand();
- _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
-
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@Id");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AccessToken");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceId");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppName");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppVersion");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceName");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@UserId");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@IsActive");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateCreated");
- _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateRevoked");
+ connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT");
+ }
}
public Task Create(AuthenticationInfo info, CancellationToken cancellationToken)
@@ -84,61 +57,76 @@ namespace MediaBrowser.Server.Implementations.Security
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
+ using (var saveInfoCommand = connection.CreateCommand())
+ {
+ saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
+
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@Id");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AccessToken");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceId");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppName");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppVersion");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceName");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@UserId");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@IsActive");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateCreated");
+ saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateRevoked");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
- var index = 0;
+ var index = 0;
- _saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id);
- _saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
- _saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
- _saveInfoCommand.GetParameter(index++).Value = info.AppName;
- _saveInfoCommand.GetParameter(index++).Value = info.AppVersion;
- _saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
- _saveInfoCommand.GetParameter(index++).Value = info.UserId;
- _saveInfoCommand.GetParameter(index++).Value = info.IsActive;
- _saveInfoCommand.GetParameter(index++).Value = info.DateCreated;
- _saveInfoCommand.GetParameter(index++).Value = info.DateRevoked;
+ saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id);
+ saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
+ saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
+ saveInfoCommand.GetParameter(index++).Value = info.AppName;
+ saveInfoCommand.GetParameter(index++).Value = info.AppVersion;
+ saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
+ saveInfoCommand.GetParameter(index++).Value = info.UserId;
+ saveInfoCommand.GetParameter(index++).Value = info.IsActive;
+ saveInfoCommand.GetParameter(index++).Value = info.DateCreated;
+ saveInfoCommand.GetParameter(index++).Value = info.DateRevoked;
- _saveInfoCommand.Transaction = transaction;
+ saveInfoCommand.Transaction = transaction;
- _saveInfoCommand.ExecuteNonQuery();
+ saveInfoCommand.ExecuteNonQuery();
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -151,101 +139,104 @@ namespace MediaBrowser.Server.Implementations.Security
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseSelectText;
-
- var whereClauses = new List<string>();
-
- var startIndex = query.StartIndex ?? 0;
-
- if (!string.IsNullOrWhiteSpace(query.AccessToken))
+ using (var cmd = connection.CreateCommand())
{
- whereClauses.Add("AccessToken=@AccessToken");
- cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken;
- }
+ cmd.CommandText = BaseSelectText;
- if (!string.IsNullOrWhiteSpace(query.UserId))
- {
- whereClauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
- }
+ var whereClauses = new List<string>();
- if (!string.IsNullOrWhiteSpace(query.DeviceId))
- {
- whereClauses.Add("DeviceId=@DeviceId");
- cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId;
- }
+ var startIndex = query.StartIndex ?? 0;
- if (query.IsActive.HasValue)
- {
- whereClauses.Add("IsActive=@IsActive");
- cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value;
- }
+ if (!string.IsNullOrWhiteSpace(query.AccessToken))
+ {
+ whereClauses.Add("AccessToken=@AccessToken");
+ cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken;
+ }
- if (query.HasUser.HasValue)
- {
- if (query.HasUser.Value)
+ if (!string.IsNullOrWhiteSpace(query.UserId))
{
- whereClauses.Add("UserId not null");
+ whereClauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
}
- else
+
+ if (!string.IsNullOrWhiteSpace(query.DeviceId))
{
- whereClauses.Add("UserId is null");
+ whereClauses.Add("DeviceId=@DeviceId");
+ cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId;
}
- }
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ if (query.IsActive.HasValue)
+ {
+ whereClauses.Add("IsActive=@IsActive");
+ cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value;
+ }
- if (startIndex > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
+ if (query.HasUser.HasValue)
+ {
+ if (query.HasUser.Value)
+ {
+ whereClauses.Add("UserId not null");
+ }
+ else
+ {
+ whereClauses.Add("UserId is null");
+ }
+ }
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
- pagingWhereText,
- startIndex.ToString(_usCulture)));
- }
+ if (startIndex > 0)
+ {
+ var pagingWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
+ pagingWhereText,
+ startIndex.ToString(_usCulture)));
+ }
- cmd.CommandText += whereText;
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- cmd.CommandText += " ORDER BY DateCreated";
+ cmd.CommandText += whereText;
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ cmd.CommandText += " ORDER BY DateCreated";
- cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging;
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- var list = new List<AuthenticationInfo>();
- var count = 0;
+ cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ var list = new List<AuthenticationInfo>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(Get(reader));
+ while (reader.Read())
+ {
+ list.Add(Get(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<AuthenticationInfo>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<AuthenticationInfo>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -256,24 +247,27 @@ namespace MediaBrowser.Server.Implementations.Security
throw new ArgumentNullException("id");
}
- var guid = new Guid(id);
-
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseSelectText + " where Id=@Id";
-
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ var guid = new Guid(id);
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ using (var cmd = connection.CreateCommand())
{
- if (reader.Read())
+ cmd.CommandText = BaseSelectText + " where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return Get(reader);
+ if (reader.Read())
+ {
+ return Get(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private AuthenticationInfo Get(IDataReader reader)
@@ -319,19 +313,5 @@ namespace MediaBrowser.Server.Implementations.Security
return info;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 4386b785a..84aab5e1f 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -932,7 +932,7 @@ namespace MediaBrowser.Server.Implementations.Session
return session.SessionController.SendGeneralCommand(command, cancellationToken);
}
- public Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
+ public async Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
{
var session = GetSessionToRemoteControl(sessionId);
@@ -950,7 +950,14 @@ namespace MediaBrowser.Server.Implementations.Session
}
else
{
- items = command.ItemIds.SelectMany(i => TranslateItemForPlayback(i, user))
+ var list = new List<BaseItem>();
+ foreach (var itemId in command.ItemIds)
+ {
+ var subItems = await TranslateItemForPlayback(itemId, user).ConfigureAwait(false);
+ list.AddRange(subItems);
+ }
+
+ items = list
.Where(i => i.LocationType != LocationType.Virtual)
.ToList();
}
@@ -1013,10 +1020,10 @@ namespace MediaBrowser.Server.Implementations.Session
command.ControllingUserId = controllingSession.UserId.Value.ToString("N");
}
- return session.SessionController.SendPlayCommand(command, cancellationToken);
+ await session.SessionController.SendPlayCommand(command, cancellationToken).ConfigureAwait(false);
}
- private IEnumerable<BaseItem> TranslateItemForPlayback(string id, User user)
+ private async Task<List<BaseItem>> TranslateItemForPlayback(string id, User user)
{
var item = _libraryManager.GetItemById(id);
@@ -1037,25 +1044,27 @@ namespace MediaBrowser.Server.Implementations.Session
});
return FilterToSingleMediaType(items)
- .OrderBy(i => i.SortName);
+ .OrderBy(i => i.SortName)
+ .ToList();
}
if (item.IsFolder)
{
var folder = (Folder)item;
- var items = folder.GetItems(new InternalItemsQuery(user)
+ var itemsResult = await folder.GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false
- }).Result.Items;
+ }).ConfigureAwait(false);
- return FilterToSingleMediaType(items)
- .OrderBy(i => i.SortName);
+ return FilterToSingleMediaType(itemsResult.Items)
+ .OrderBy(i => i.SortName)
+ .ToList();
}
- return new[] { item };
+ return new List<BaseItem> { item };
}
private IEnumerable<BaseItem> FilterToSingleMediaType(IEnumerable<BaseItem> items)
@@ -1125,11 +1134,11 @@ namespace MediaBrowser.Server.Implementations.Session
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+ public async Task SendRestartRequiredNotification(CancellationToken cancellationToken)
{
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
- var info = _appHost.GetSystemInfo();
+ var info = await _appHost.GetSystemInfo().ConfigureAwait(false);
var tasks = sessions.Select(session => Task.Run(async () =>
{
@@ -1144,7 +1153,7 @@ namespace MediaBrowser.Server.Implementations.Session
}, cancellationToken));
- return Task.WhenAll(tasks);
+ await Task.WhenAll(tasks).ConfigureAwait(false);
}
/// <summary>
@@ -1451,7 +1460,7 @@ namespace MediaBrowser.Server.Implementations.Session
}
}
- public async Task RevokeUserTokens(string userId)
+ public async Task RevokeUserTokens(string userId, string currentAccessToken)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
@@ -1461,7 +1470,10 @@ namespace MediaBrowser.Server.Implementations.Session
foreach (var info in existing.Items)
{
- await Logout(info.AccessToken).ConfigureAwait(false);
+ if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
+ {
+ await Logout(info.AccessToken).ConfigureAwait(false);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Social/SharingManager.cs b/MediaBrowser.Server.Implementations/Social/SharingManager.cs
index 2ffd33ca4..95f0ece0c 100644
--- a/MediaBrowser.Server.Implementations/Social/SharingManager.cs
+++ b/MediaBrowser.Server.Implementations/Social/SharingManager.cs
@@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Social
throw new ResourceNotFoundException();
}
- var externalUrl = _appHost.GetSystemInfo().WanAddress;
+ var externalUrl = (await _appHost.GetSystemInfo().ConfigureAwait(false)).WanAddress;
if (string.IsNullOrWhiteSpace(externalUrl))
{
@@ -58,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Social
UserId = userId
};
- AddShareInfo(info);
+ AddShareInfo(info, externalUrl);
await _repository.CreateShare(info).ConfigureAwait(false);
@@ -74,15 +74,13 @@ namespace MediaBrowser.Server.Implementations.Social
{
var info = _repository.GetShareInfo(id);
- AddShareInfo(info);
+ AddShareInfo(info, _appHost.GetSystemInfo().Result.WanAddress);
return info;
}
- private void AddShareInfo(SocialShareInfo info)
+ private void AddShareInfo(SocialShareInfo info, string externalUrl)
{
- var externalUrl = _appHost.GetSystemInfo().WanAddress;
-
info.ImageUrl = externalUrl + "/Social/Shares/Public/" + info.Id + "/Image";
info.Url = externalUrl + "/emby/web/shared.html?id=" + info.Id;
diff --git a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
index 317743eb1..c4243c1a7 100644
--- a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
+++ b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
@@ -12,54 +12,30 @@ namespace MediaBrowser.Server.Implementations.Social
{
public class SharingRepository : BaseSqliteRepository
{
- private IDbConnection _connection;
- private IDbCommand _saveShareCommand;
- private readonly IApplicationPaths _appPaths;
-
- public SharingRepository(ILogManager logManager, IApplicationPaths appPaths)
- : base(logManager)
+ public SharingRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector dbConnector)
+ : base(logManager, dbConnector)
{
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "shares.db");
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "shares.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists Shares (Id GUID, ItemId TEXT, UserId TEXT, ExpirationDate DateTime, PRIMARY KEY (Id))",
"create index if not exists idx_Shares on Shares(Id)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
-
- PrepareStatements();
- }
-
- /// <summary>
- /// Prepares the statements.
- /// </summary>
- private void PrepareStatements()
- {
- _saveShareCommand = _connection.CreateCommand();
- _saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)";
-
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@Id");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@ItemId");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@UserId");
- _saveShareCommand.Parameters.Add(_saveShareCommand, "@ExpirationDate");
+ connection.RunQueries(queries, Logger);
+ }
}
public async Task CreateShare(SocialShareInfo info)
@@ -77,53 +53,62 @@ namespace MediaBrowser.Server.Implementations.Social
cancellationToken.ThrowIfCancellationRequested();
- await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- _saveShareCommand.GetParameter(0).Value = new Guid(info.Id);
- _saveShareCommand.GetParameter(1).Value = info.ItemId;
- _saveShareCommand.GetParameter(2).Value = info.UserId;
- _saveShareCommand.GetParameter(3).Value = info.ExpirationDate;
-
- _saveShareCommand.Transaction = transaction;
-
- _saveShareCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- catch (Exception e)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- Logger.ErrorException("Failed to save share:", e);
-
- if (transaction != null)
+ using (var saveShareCommand = connection.CreateCommand())
{
- transaction.Rollback();
+ saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)";
+
+ saveShareCommand.Parameters.Add(saveShareCommand, "@Id");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@ItemId");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@UserId");
+ saveShareCommand.Parameters.Add(saveShareCommand, "@ExpirationDate");
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ saveShareCommand.GetParameter(0).Value = new Guid(info.Id);
+ saveShareCommand.GetParameter(1).Value = info.ItemId;
+ saveShareCommand.GetParameter(2).Value = info.UserId;
+ saveShareCommand.GetParameter(3).Value = info.ExpirationDate;
+
+ saveShareCommand.Transaction = transaction;
+
+ saveShareCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save share:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
-
- WriteLock.Release();
}
}
@@ -134,20 +119,23 @@ namespace MediaBrowser.Server.Implementations.Social
throw new ArgumentNullException("id");
}
- var cmd = _connection.CreateCommand();
- cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id";
+ using (var connection = CreateConnection(true).Result)
+ {
+ var cmd = connection.CreateCommand();
+ cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id";
- cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id);
+ cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id);
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetSocialShareInfo(reader);
+ if (reader.Read())
+ {
+ return GetSocialShareInfo(reader);
+ }
}
- }
- return null;
+ return null;
+ }
}
private SocialShareInfo GetSocialShareInfo(IDataReader reader)
@@ -164,21 +152,7 @@ namespace MediaBrowser.Server.Implementations.Social
public async Task DeleteShare(string id)
{
-
- }
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 886308d43..e120d3a4d 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -234,10 +234,22 @@ namespace MediaBrowser.Server.Implementations.Sync
public async Task<IEnumerable<BaseItem>> GetItemsForSync(SyncCategory? category, string parentId, IEnumerable<string> itemIds, User user, bool unwatchedOnly)
{
- var items = category.HasValue ?
- await GetItemsForSync(category.Value, parentId, user).ConfigureAwait(false) :
- itemIds.SelectMany(i => GetItemsForSync(i, user));
+ var list = new List<BaseItem>();
+ if (category.HasValue)
+ {
+ list = (await GetItemsForSync(category.Value, parentId, user).ConfigureAwait(false)).ToList();
+ }
+ else
+ {
+ foreach (var itemId in itemIds)
+ {
+ var subList = await GetItemsForSync(itemId, user).ConfigureAwait(false);
+ list.AddRange(subList);
+ }
+ }
+
+ IEnumerable<BaseItem> items = list;
items = items.Where(_syncManager.SupportsSync);
if (unwatchedOnly)
@@ -314,7 +326,7 @@ namespace MediaBrowser.Server.Implementations.Sync
return result.Items;
}
- private IEnumerable<BaseItem> GetItemsForSync(string id, User user)
+ private async Task<List<BaseItem>> GetItemsForSync(string id, User user)
{
var item = _libraryManager.GetItemById(id);
@@ -330,18 +342,20 @@ namespace MediaBrowser.Server.Implementations.Sync
{
IsFolder = false,
Recursive = true
- });
+ }).ToList();
}
if (item.IsFolder)
{
var folder = (Folder)item;
- var items = folder.GetItems(new InternalItemsQuery(user)
+ var itemsResult = await folder.GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false
- }).Result.Items;
+ }).ConfigureAwait(false);
+
+ var items = itemsResult.Items;
if (!folder.IsPreSorted)
{
@@ -349,10 +363,10 @@ namespace MediaBrowser.Server.Implementations.Sync
.ToArray();
}
- return items;
+ return items.ToList();
}
- return new[] { item };
+ return new List<BaseItem> { item };
}
private async Task EnsureSyncJobItems(string targetId, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
index 739d1ab6e..a1ed66a99 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
@@ -18,34 +18,22 @@ namespace MediaBrowser.Server.Implementations.Sync
{
public class SyncRepository : BaseSqliteRepository, ISyncRepository
{
- private IDbConnection _connection;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private IDbCommand _insertJobCommand;
- private IDbCommand _updateJobCommand;
- private IDbCommand _deleteJobCommand;
-
- private IDbCommand _deleteJobItemsCommand;
- private IDbCommand _insertJobItemCommand;
- private IDbCommand _updateJobItemCommand;
-
private readonly IJsonSerializer _json;
- private readonly IServerApplicationPaths _appPaths;
- public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths)
- : base(logManager)
+ public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths, IDbConnector connector)
+ : base(logManager, connector)
{
_json = json;
- _appPaths = appPaths;
+ DbFilePath = Path.Combine(appPaths.DataPath, "sync14.db");
}
- public async Task Initialize(IDbConnector dbConnector)
+ public async Task Initialize()
{
- var dbFile = Path.Combine(_appPaths.DataPath, "sync14.db");
-
- _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
-
- string[] queries = {
+ using (var connection = await CreateConnection().ConfigureAwait(false))
+ {
+ string[] queries = {
"create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Profile TEXT, Quality TEXT, Bitrate INT, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
"create index if not exists idx_SyncJobs on SyncJobs(Id)",
@@ -55,120 +43,15 @@ namespace MediaBrowser.Server.Implementations.Sync
"create index if not exists idx_SyncJobItems1 on SyncJobItems(Id)",
"create index if not exists idx_SyncJobItems2 on SyncJobItems(TargetId)",
- //pragmas
- "pragma temp_store = memory",
-
"pragma shrink_memory"
};
- _connection.RunQueries(queries, Logger);
+ connection.RunQueries(queries, Logger);
- _connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT");
- _connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT");
- _connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT");
-
- PrepareStatements();
- }
-
- private void PrepareStatements()
- {
- // _deleteJobCommand
- _deleteJobCommand = _connection.CreateCommand();
- _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id";
- _deleteJobCommand.Parameters.Add(_deleteJobCommand, "@Id");
-
- // _deleteJobItemsCommand
- _deleteJobItemsCommand = _connection.CreateCommand();
- _deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId";
- _deleteJobItemsCommand.Parameters.Add(_deleteJobItemsCommand, "@JobId");
-
- // _insertJobCommand
- _insertJobCommand = _connection.CreateCommand();
- _insertJobCommand.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
-
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Id");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@TargetId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Name");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Profile");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Quality");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Bitrate");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Status");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Progress");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@UserId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemIds");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@Category");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ParentId");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@UnwatchedOnly");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemLimit");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@SyncNewContent");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateCreated");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateLastModified");
- _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemCount");
-
- // _updateJobCommand
- _updateJobCommand = _connection.CreateCommand();
- _updateJobCommand.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id";
-
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Id");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@TargetId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Name");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Profile");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Quality");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Bitrate");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Status");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Progress");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@UserId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemIds");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@Category");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ParentId");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@UnwatchedOnly");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemLimit");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@SyncNewContent");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateCreated");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateLastModified");
- _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemCount");
-
- // _insertJobItemCommand
- _insertJobItemCommand = _connection.CreateCommand();
- _insertJobItemCommand.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)";
-
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Id");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemName");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSourceId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TemporaryPath");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@OutputPath");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Status");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TargetId");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@DateCreated");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Progress");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@AdditionalFiles");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSource");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@IsMarkedForRemoval");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobItemIndex");
- _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemDateModifiedTicks");
-
- // _updateJobItemCommand
- _updateJobItemCommand = _connection.CreateCommand();
- _updateJobItemCommand.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id";
-
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Id");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemName");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSourceId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TemporaryPath");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@OutputPath");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Status");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TargetId");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@DateCreated");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Progress");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@AdditionalFiles");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSource");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@IsMarkedForRemoval");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobItemIndex");
- _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemDateModifiedTicks");
+ connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT");
+ connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT");
+ connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT");
+ }
}
private const string BaseJobSelectText = "select Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
@@ -182,7 +65,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
+
var guid = new Guid(id);
if (guid == Guid.Empty)
@@ -190,22 +73,25 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentNullException("id");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobSelectText + " where Id=@Id";
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobSelectText + " where Id=@Id";
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetJob(reader);
+ if (reader.Read())
+ {
+ return GetJob(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private SyncJob GetJob(IDataReader reader)
@@ -283,15 +169,15 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Create(SyncJob job)
{
- return InsertOrUpdate(job, _insertJobCommand);
+ return InsertOrUpdate(job, true);
}
public Task Update(SyncJob job)
{
- return InsertOrUpdate(job, _updateJobCommand);
+ return InsertOrUpdate(job, false);
}
- private async Task InsertOrUpdate(SyncJob job, IDbCommand cmd)
+ private async Task InsertOrUpdate(SyncJob job, bool insert)
{
if (job == null)
{
@@ -299,70 +185,119 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
-
- IDbTransaction transaction = null;
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- cmd.GetParameter(index++).Value = new Guid(job.Id);
- cmd.GetParameter(index++).Value = job.TargetId;
- cmd.GetParameter(index++).Value = job.Name;
- cmd.GetParameter(index++).Value = job.Profile;
- cmd.GetParameter(index++).Value = job.Quality;
- cmd.GetParameter(index++).Value = job.Bitrate;
- cmd.GetParameter(index++).Value = job.Status.ToString();
- cmd.GetParameter(index++).Value = job.Progress;
- cmd.GetParameter(index++).Value = job.UserId;
- cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray());
- cmd.GetParameter(index++).Value = job.Category;
- cmd.GetParameter(index++).Value = job.ParentId;
- cmd.GetParameter(index++).Value = job.UnwatchedOnly;
- cmd.GetParameter(index++).Value = job.ItemLimit;
- cmd.GetParameter(index++).Value = job.SyncNewContent;
- cmd.GetParameter(index++).Value = job.DateCreated;
- cmd.GetParameter(index++).Value = job.DateLastModified;
- cmd.GetParameter(index++).Value = job.ItemCount;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ if (insert)
+ {
+ cmd.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@Name");
+ cmd.Parameters.Add(cmd, "@Profile");
+ cmd.Parameters.Add(cmd, "@Quality");
+ cmd.Parameters.Add(cmd, "@Bitrate");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@UserId");
+ cmd.Parameters.Add(cmd, "@ItemIds");
+ cmd.Parameters.Add(cmd, "@Category");
+ cmd.Parameters.Add(cmd, "@ParentId");
+ cmd.Parameters.Add(cmd, "@UnwatchedOnly");
+ cmd.Parameters.Add(cmd, "@ItemLimit");
+ cmd.Parameters.Add(cmd, "@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateLastModified");
+ cmd.Parameters.Add(cmd, "@ItemCount");
+ }
+ else
+ {
+ cmd.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@Name");
+ cmd.Parameters.Add(cmd, "@Profile");
+ cmd.Parameters.Add(cmd, "@Quality");
+ cmd.Parameters.Add(cmd, "@Bitrate");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@UserId");
+ cmd.Parameters.Add(cmd, "@ItemIds");
+ cmd.Parameters.Add(cmd, "@Category");
+ cmd.Parameters.Add(cmd, "@ParentId");
+ cmd.Parameters.Add(cmd, "@UnwatchedOnly");
+ cmd.Parameters.Add(cmd, "@ItemLimit");
+ cmd.Parameters.Add(cmd, "@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@DateLastModified");
+ cmd.Parameters.Add(cmd, "@ItemCount");
+ }
- cmd.ExecuteNonQuery();
+ IDbTransaction transaction = null;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ cmd.GetParameter(index++).Value = new Guid(job.Id);
+ cmd.GetParameter(index++).Value = job.TargetId;
+ cmd.GetParameter(index++).Value = job.Name;
+ cmd.GetParameter(index++).Value = job.Profile;
+ cmd.GetParameter(index++).Value = job.Quality;
+ cmd.GetParameter(index++).Value = job.Bitrate;
+ cmd.GetParameter(index++).Value = job.Status.ToString();
+ cmd.GetParameter(index++).Value = job.Progress;
+ cmd.GetParameter(index++).Value = job.UserId;
+ cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray());
+ cmd.GetParameter(index++).Value = job.Category;
+ cmd.GetParameter(index++).Value = job.ParentId;
+ cmd.GetParameter(index++).Value = job.UnwatchedOnly;
+ cmd.GetParameter(index++).Value = job.ItemLimit;
+ cmd.GetParameter(index++).Value = job.SyncNewContent;
+ cmd.GetParameter(index++).Value = job.DateCreated;
+ cmd.GetParameter(index++).Value = job.DateLastModified;
+ cmd.GetParameter(index++).Value = job.ItemCount;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -374,56 +309,66 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- _deleteJobCommand.GetParameter(index++).Value = new Guid(id);
- _deleteJobCommand.Transaction = transaction;
- _deleteJobCommand.ExecuteNonQuery();
-
- index = 0;
- _deleteJobItemsCommand.GetParameter(index++).Value = id;
- _deleteJobItemsCommand.Transaction = transaction;
- _deleteJobItemsCommand.ExecuteNonQuery();
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
- throw;
- }
- catch (Exception e)
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- Logger.ErrorException("Failed to save record:", e);
-
- if (transaction != null)
+ using (var deleteJobCommand = connection.CreateCommand())
{
- transaction.Rollback();
- }
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ using (var deleteJobItemsCommand = connection.CreateCommand())
+ {
+ IDbTransaction transaction = null;
+
+ try
+ {
+ // _deleteJobCommand
+ deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id";
+ deleteJobCommand.Parameters.Add(deleteJobCommand, "@Id");
+
+ transaction = connection.BeginTransaction();
+
+ deleteJobCommand.GetParameter(0).Value = new Guid(id);
+ deleteJobCommand.Transaction = transaction;
+ deleteJobCommand.ExecuteNonQuery();
+
+ // _deleteJobItemsCommand
+ deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId";
+ deleteJobItemsCommand.Parameters.Add(deleteJobItemsCommand, "@JobId");
+
+ deleteJobItemsCommand.GetParameter(0).Value = id;
+ deleteJobItemsCommand.Transaction = transaction;
+ deleteJobItemsCommand.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -435,83 +380,86 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- using (var cmd = _connection.CreateCommand())
+
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobSelectText;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobSelectText;
- var whereClauses = new List<string>();
+ var whereClauses = new List<string>();
- if (query.Statuses.Length > 0)
- {
- var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
+ if (query.Statuses.Length > 0)
+ {
+ var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
- whereClauses.Add(string.Format("Status in ({0})", statuses));
- }
- if (!string.IsNullOrWhiteSpace(query.TargetId))
- {
- whereClauses.Add("TargetId=@TargetId");
- cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
- }
- if (!string.IsNullOrWhiteSpace(query.UserId))
- {
- whereClauses.Add("UserId=@UserId");
- cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
- }
- if (query.SyncNewContent.HasValue)
- {
- whereClauses.Add("SyncNewContent=@SyncNewContent");
- cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value;
- }
+ whereClauses.Add(string.Format("Status in ({0})", statuses));
+ }
+ if (!string.IsNullOrWhiteSpace(query.TargetId))
+ {
+ whereClauses.Add("TargetId=@TargetId");
+ cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.UserId))
+ {
+ whereClauses.Add("UserId=@UserId");
+ cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId;
+ }
+ if (query.SyncNewContent.HasValue)
+ {
+ whereClauses.Add("SyncNewContent=@SyncNewContent");
+ cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value;
+ }
- cmd.CommandText += " mainTable";
+ cmd.CommandText += " mainTable";
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var startIndex = query.StartIndex ?? 0;
- if (startIndex > 0)
- {
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})",
- startIndex.ToString(_usCulture)));
- }
+ var startIndex = query.StartIndex ?? 0;
+ if (startIndex > 0)
+ {
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})",
+ startIndex.ToString(_usCulture)));
+ }
- if (whereClauses.Count > 0)
- {
- cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
- }
+ if (whereClauses.Count > 0)
+ {
+ cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
+ }
- cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC";
+ cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC";
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging;
+ cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging;
- var list = new List<SyncJob>();
- var count = 0;
+ var list = new List<SyncJob>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(GetJob(reader));
+ while (reader.Read())
+ {
+ list.Add(GetJob(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<SyncJob>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<SyncJob>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -523,25 +471,28 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
+
var guid = new Guid(id);
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = BaseJobItemSelectText + " where Id=@Id";
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = BaseJobItemSelectText + " where Id=@Id";
- cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
+ cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
- return GetJobItem(reader);
+ if (reader.Read())
+ {
+ return GetJobItem(reader);
+ }
}
}
- }
- return null;
+ return null;
+ }
}
private QueryResult<T> GetJobItemReader<T>(SyncJobItemQuery query, string baseSelectText, Func<IDataReader, T> itemFactory)
@@ -551,81 +502,84 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new ArgumentNullException("query");
}
- using (var cmd = _connection.CreateCommand())
+ using (var connection = CreateConnection(true).Result)
{
- cmd.CommandText = baseSelectText;
+ using (var cmd = connection.CreateCommand())
+ {
+ cmd.CommandText = baseSelectText;
- var whereClauses = new List<string>();
+ var whereClauses = new List<string>();
- if (!string.IsNullOrWhiteSpace(query.JobId))
- {
- whereClauses.Add("JobId=@JobId");
- cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId;
- }
- if (!string.IsNullOrWhiteSpace(query.ItemId))
- {
- whereClauses.Add("ItemId=@ItemId");
- cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId;
- }
- if (!string.IsNullOrWhiteSpace(query.TargetId))
- {
- whereClauses.Add("TargetId=@TargetId");
- cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
- }
+ if (!string.IsNullOrWhiteSpace(query.JobId))
+ {
+ whereClauses.Add("JobId=@JobId");
+ cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.ItemId))
+ {
+ whereClauses.Add("ItemId=@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId;
+ }
+ if (!string.IsNullOrWhiteSpace(query.TargetId))
+ {
+ whereClauses.Add("TargetId=@TargetId");
+ cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
+ }
- if (query.Statuses.Length > 0)
- {
- var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
+ if (query.Statuses.Length > 0)
+ {
+ var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
- whereClauses.Add(string.Format("Status in ({0})", statuses));
- }
+ whereClauses.Add(string.Format("Status in ({0})", statuses));
+ }
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
- var startIndex = query.StartIndex ?? 0;
- if (startIndex > 0)
- {
- whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})",
- startIndex.ToString(_usCulture)));
- }
+ var startIndex = query.StartIndex ?? 0;
+ if (startIndex > 0)
+ {
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})",
+ startIndex.ToString(_usCulture)));
+ }
- if (whereClauses.Count > 0)
- {
- cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
- }
+ if (whereClauses.Count > 0)
+ {
+ cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
+ }
- cmd.CommandText += " ORDER BY JobItemIndex, DateCreated";
+ cmd.CommandText += " ORDER BY JobItemIndex, DateCreated";
- if (query.Limit.HasValue)
- {
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
- }
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
+ }
- cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
+ cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
- var list = new List<T>();
- var count = 0;
+ var list = new List<T>();
+ var count = 0;
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
- {
- while (reader.Read())
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
- list.Add(itemFactory(reader));
+ while (reader.Read())
+ {
+ list.Add(itemFactory(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
}
- if (reader.NextResult() && reader.Read())
+ return new QueryResult<T>()
{
- count = reader.GetInt32(0);
- }
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
}
-
- return new QueryResult<T>()
- {
- Items = list.ToArray(),
- TotalRecordCount = count
- };
}
}
@@ -641,15 +595,15 @@ namespace MediaBrowser.Server.Implementations.Sync
public Task Create(SyncJobItem jobItem)
{
- return InsertOrUpdate(jobItem, _insertJobItemCommand);
+ return InsertOrUpdate(jobItem, true);
}
public Task Update(SyncJobItem jobItem)
{
- return InsertOrUpdate(jobItem, _updateJobItemCommand);
+ return InsertOrUpdate(jobItem, false);
}
- private async Task InsertOrUpdate(SyncJobItem jobItem, IDbCommand cmd)
+ private async Task InsertOrUpdate(SyncJobItem jobItem, bool insert)
{
if (jobItem == null)
{
@@ -657,68 +611,114 @@ namespace MediaBrowser.Server.Implementations.Sync
}
CheckDisposed();
-
- await WriteLock.WaitAsync().ConfigureAwait(false);
- IDbTransaction transaction = null;
-
- try
+ using (var connection = await CreateConnection().ConfigureAwait(false))
{
- transaction = _connection.BeginTransaction();
-
- var index = 0;
-
- cmd.GetParameter(index++).Value = new Guid(jobItem.Id);
- cmd.GetParameter(index++).Value = jobItem.ItemId;
- cmd.GetParameter(index++).Value = jobItem.ItemName;
- cmd.GetParameter(index++).Value = jobItem.MediaSourceId;
- cmd.GetParameter(index++).Value = jobItem.JobId;
- cmd.GetParameter(index++).Value = jobItem.TemporaryPath;
- cmd.GetParameter(index++).Value = jobItem.OutputPath;
- cmd.GetParameter(index++).Value = jobItem.Status.ToString();
- cmd.GetParameter(index++).Value = jobItem.TargetId;
- cmd.GetParameter(index++).Value = jobItem.DateCreated;
- cmd.GetParameter(index++).Value = jobItem.Progress;
- cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles);
- cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource);
- cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval;
- cmd.GetParameter(index++).Value = jobItem.JobItemIndex;
- cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks;
-
- cmd.Transaction = transaction;
+ using (var cmd = connection.CreateCommand())
+ {
+ if (insert)
+ {
+ cmd.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemName");
+ cmd.Parameters.Add(cmd, "@MediaSourceId");
+ cmd.Parameters.Add(cmd, "@JobId");
+ cmd.Parameters.Add(cmd, "@TemporaryPath");
+ cmd.Parameters.Add(cmd, "@OutputPath");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@AdditionalFiles");
+ cmd.Parameters.Add(cmd, "@MediaSource");
+ cmd.Parameters.Add(cmd, "@IsMarkedForRemoval");
+ cmd.Parameters.Add(cmd, "@JobItemIndex");
+ cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks");
+ }
+ else
+ {
+ // cmd
+ cmd.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id";
+
+ cmd.Parameters.Add(cmd, "@Id");
+ cmd.Parameters.Add(cmd, "@ItemId");
+ cmd.Parameters.Add(cmd, "@ItemName");
+ cmd.Parameters.Add(cmd, "@MediaSourceId");
+ cmd.Parameters.Add(cmd, "@JobId");
+ cmd.Parameters.Add(cmd, "@TemporaryPath");
+ cmd.Parameters.Add(cmd, "@OutputPath");
+ cmd.Parameters.Add(cmd, "@Status");
+ cmd.Parameters.Add(cmd, "@TargetId");
+ cmd.Parameters.Add(cmd, "@DateCreated");
+ cmd.Parameters.Add(cmd, "@Progress");
+ cmd.Parameters.Add(cmd, "@AdditionalFiles");
+ cmd.Parameters.Add(cmd, "@MediaSource");
+ cmd.Parameters.Add(cmd, "@IsMarkedForRemoval");
+ cmd.Parameters.Add(cmd, "@JobItemIndex");
+ cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks");
+ }
- cmd.ExecuteNonQuery();
+ IDbTransaction transaction = null;
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ try
+ {
+ transaction = connection.BeginTransaction();
+
+ var index = 0;
+
+ cmd.GetParameter(index++).Value = new Guid(jobItem.Id);
+ cmd.GetParameter(index++).Value = jobItem.ItemId;
+ cmd.GetParameter(index++).Value = jobItem.ItemName;
+ cmd.GetParameter(index++).Value = jobItem.MediaSourceId;
+ cmd.GetParameter(index++).Value = jobItem.JobId;
+ cmd.GetParameter(index++).Value = jobItem.TemporaryPath;
+ cmd.GetParameter(index++).Value = jobItem.OutputPath;
+ cmd.GetParameter(index++).Value = jobItem.Status.ToString();
+ cmd.GetParameter(index++).Value = jobItem.TargetId;
+ cmd.GetParameter(index++).Value = jobItem.DateCreated;
+ cmd.GetParameter(index++).Value = jobItem.Progress;
+ cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles);
+ cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource);
+ cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval;
+ cmd.GetParameter(index++).Value = jobItem.JobItemIndex;
+ cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks;
+
+ cmd.Transaction = transaction;
+
+ cmd.ExecuteNonQuery();
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- catch (Exception e)
- {
- Logger.ErrorException("Failed to save record:", e);
+ throw;
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorException("Failed to save record:", e);
- if (transaction != null)
- {
- transaction.Rollback();
- }
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+ }
}
-
- WriteLock.Release();
}
}
@@ -809,19 +809,5 @@ namespace MediaBrowser.Server.Implementations.Sync
return item;
}
-
- protected override void CloseConnection()
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
index d57aea08e..82232ffae 100644
--- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
+++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
@@ -124,58 +124,80 @@ namespace MediaBrowser.Server.Implementations.TV
/// <returns>Task{Episode}.</returns>
private Tuple<Episode, DateTime, bool> GetNextUp(Series series, User user)
{
- // Get them in display order, then reverse
- var allEpisodes = series.GetEpisodes(user, false, false)
- .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0)
- .Reverse()
- .ToList();
-
- Episode lastWatched = null;
- var lastWatchedDate = DateTime.MinValue;
- Episode nextUp = null;
-
- var unplayedEpisodes = new List<Episode>();
-
- // Go back starting with the most recent episodes
- foreach (var episode in allEpisodes)
+ var firstUnwatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- var userData = _userDataManager.GetUserData(user, episode);
-
- if (userData.Played)
- {
- if (lastWatched != null || nextUp == null)
- {
- break;
- }
-
- lastWatched = episode;
- lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
- }
- else
- {
- unplayedEpisodes.Add(episode);
+ AncestorWithPresentationUniqueKey = series.PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.SortName },
+ SortOrder = SortOrder.Ascending,
+ Limit = 1,
+ IsPlayed = false,
+ IsVirtualItem = false,
+ ParentIndexNumberNotEquals = 0
- nextUp = episode;
- }
- }
+ }).Cast<Episode>().FirstOrDefault();
- if (lastWatched != null)
+ // series is fully played
+ if (firstUnwatchedEpisode == null)
{
- return new Tuple<Episode, DateTime, bool>(nextUp, lastWatchedDate, false);
+ return new Tuple<Episode, DateTime, bool>(null, DateTime.MinValue, true);
}
- Episode firstEpisode = null;
- // Find the first unplayed episode. Start from the back of the list since they're in reverse order
- for (var i = unplayedEpisodes.Count - 1; i >= 0; i--)
+ var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- var unplayedEpisode = unplayedEpisodes[i];
+ AncestorWithPresentationUniqueKey = series.PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.DatePlayed },
+ SortOrder = SortOrder.Descending,
+ Limit = 1,
+ IsVirtualItem = false,
+ ParentIndexNumberNotEquals = 0
+
+ }).FirstOrDefault();
+
+ //// Get them in display order, then reverse
+ //var allEpisodes = series.GetEpisodes(user, false, false)
+ // .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0)
+ // .Reverse()
+ // .ToList();
+
+ //Episode lastWatched = null;
+ //var lastWatchedDate = DateTime.MinValue;
+ //Episode nextUp = null;
+
+ //// Go back starting with the most recent episodes
+ //foreach (var episode in allEpisodes)
+ //{
+ // var userData = _userDataManager.GetUserData(user, episode);
+
+ // if (userData.Played)
+ // {
+ // if (lastWatched != null || nextUp == null)
+ // {
+ // break;
+ // }
+
+ // lastWatched = episode;
+ // lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue;
+ // }
+ // else
+ // {
+ // nextUp = episode;
+ // }
+ //}
+
+ if (lastWatchedEpisode != null)
+ {
+ var userData = _userDataManager.GetUserData(user, lastWatchedEpisode);
- firstEpisode = unplayedEpisode;
- break;
+ if (userData.LastPlayedDate.HasValue)
+ {
+ return new Tuple<Episode, DateTime, bool>(firstUnwatchedEpisode, userData.LastPlayedDate.Value, false);
+ }
}
// Return the first episode
- return new Tuple<Episode, DateTime, bool>(firstEpisode, DateTime.MinValue, true);
+ return new Tuple<Episode, DateTime, bool>(firstUnwatchedEpisode, DateTime.MinValue, true);
}
private QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, int? totalRecordLimit, NextUpQuery query)
diff --git a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
index 40c4deb19..32992b9b2 100644
--- a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
+++ b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs
@@ -96,20 +96,20 @@ namespace MediaBrowser.Server.Implementations.Udp
private async void RespondToV1Message(string endpoint, Encoding encoding)
{
- var localAddress = _appHost.LocalApiUrl;
+ var localUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
- if (!string.IsNullOrEmpty(localAddress))
+ if (!string.IsNullOrEmpty(localUrl))
{
// This is how we did the old v1 search, so need to strip off the protocol
- var index = localAddress.IndexOf("://", StringComparison.OrdinalIgnoreCase);
+ var index = localUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
- localAddress = localAddress.Substring(index + 3);
+ localUrl = localUrl.Substring(index + 3);
}
// Send a response back with our ip address and port
- var response = String.Format("MediaBrowserServer|{0}", localAddress);
+ var response = String.Format("MediaBrowserServer|{0}", localUrl);
await SendAsync(Encoding.UTF8.GetBytes(response), endpoint);
}
@@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Udp
private async void RespondToV2Message(string endpoint, Encoding encoding)
{
- var localUrl = _appHost.LocalApiUrl;
+ var localUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
if (!string.IsNullOrEmpty(localUrl))
{
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 516bf3271..326721ff3 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
- <package id="Emby.XmlTv" version="1.0.0.50" targetFramework="net45" />
+ <package id="Emby.XmlTv" version="1.0.0.53" targetFramework="net45" />
<package id="ini-parser" version="2.3.0" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
- <package id="MediaBrowser.Naming" version="1.0.0.51" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.52" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index b61281f1b..aae9804fb 100644
--- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -87,6 +87,10 @@
<Reference Include="CommonIO">
<HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath>
</Reference>
+ <Reference Include="System.Data.SQLite">
+ <HintPath>..\ThirdParty\System.Data.SQLite.ManagedOnly\1.0.94.0\System.Data.SQLite.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
@@ -113,6 +117,7 @@
<Compile Include="..\MediaBrowser.Server.Mono\Networking\CertificateGenerator.cs">
<Link>Native\CertificateGenerator.cs</Link>
</Compile>
+ <Compile Include="Native\SqliteExtensions.cs" />
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="MainMenu.xib" />
@@ -394,9 +399,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvstatus.html">
<Link>Resources\dashboard-ui\livetvstatus.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtimer.html">
- <Link>Resources\dashboard-ui\livetvtimer.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtunerprovider-hdhomerun.html">
<Link>Resources\dashboard-ui\livetvtunerprovider-hdhomerun.html</Link>
</BundleResource>
@@ -916,21 +918,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\Swiper\src\less\swiper.less">
<Link>Resources\dashboard-ui\bower_components\Swiper\src\less\swiper.less</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\alameda\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\alameda\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\alameda\LICENSE">
- <Link>Resources\dashboard-ui\bower_components\alameda\LICENSE</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\alameda\alameda.js">
- <Link>Resources\dashboard-ui\bower_components\alameda\alameda.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\alameda\bower.json">
- <Link>Resources\dashboard-ui\bower_components\alameda\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\alameda\shrinktest.sh">
- <Link>Resources\dashboard-ui\bower_components\alameda\shrinktest.sh</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\cryptojslib\.bower.json">
<Link>Resources\dashboard-ui\bower_components\cryptojslib\.bower.json</Link>
</BundleResource>
@@ -1303,33 +1290,45 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\browserdeviceprofile.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\browserdeviceprofile.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\clearbutton.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\clearbutton.css</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\datetime.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\datetime.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\fetchhelper.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\fetchhelper.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\filedownloader.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\filedownloader.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\focusmanager.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\focusmanager.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\formdialog.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\formdialog.css</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\globalize.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\globalize.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\itemcontextmenu.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\itemcontextmenu.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\itemhelper.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\itemhelper.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\layoutmanager.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\layoutmanager.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\multidownload.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\multidownload.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\objectassign.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\objectassign.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\qualityoptions.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\qualityoptions.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\requirecss.js">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\requirecss.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\requirehtml.js">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\requirehtml.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\router.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\router.js</Link>
</BundleResource>
@@ -1342,12 +1341,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\servernotifications.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\servernotifications.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\shell.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\shell.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\usersettings.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\usersettings.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\viewmanager.js">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\viewmanager.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\visibleinviewport.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\visibleinviewport.js</Link>
</BundleResource>
@@ -1570,6 +1572,21 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\fonts\roboto\ty9dfvLAziwdqQ2dHoyjphTbgVql8nDJpwnrE27mub0.woff2">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\fonts\roboto\ty9dfvLAziwdqQ2dHoyjphTbgVql8nDJpwnrE27mub0.woff2</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\guide\guide.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\guide\guide.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\guide\guide.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\guide\guide.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\guide\tvguide.template.html">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\guide\tvguide.template.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\icons\mediainfo.html">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\icons\mediainfo.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\icons\nav.html">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\icons\nav.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\images\basicimagefetcher.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\images\basicimagefetcher.js</Link>
</BundleResource>
@@ -1594,12 +1611,21 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\loading\loading.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\loading\loading.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\mediainfo\fresh.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\mediainfo\fresh.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\mediainfo\mediainfo.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\mediainfo\mediainfo.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\mediainfo\mediainfo.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\mediainfo\mediainfo.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\mediainfo\rotten.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\mediainfo\rotten.png</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\page.js\page.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\page.js\page.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\prompt\icons.html">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\prompt\icons.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\prompt\nativeprompt.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\prompt\nativeprompt.js</Link>
</BundleResource>
@@ -1609,6 +1635,63 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\prompt\style.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\prompt\style.css</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.template.html">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.template.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingeditor.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingeditor.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingeditor.template.html">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingeditor.template.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\require\requirecss.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\require\requirecss.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\require\requirehtml.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\require\requirehtml.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\require\requiretext.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\require\requiretext.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\sharingmanager.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\sharingmanager.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\sharingmenu.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\sharingmenu.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\LICENSE">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\LICENSE</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\README.md">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\css\social-share-kit.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\css\social-share-kit.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.eot">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.eot</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.svg">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.svg</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.ttf">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.ttf</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.woff">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\fonts\social-share-kit.woff</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\js\social-share-kit.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\js\social-share-kit.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\js\social-share-kit.min.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sharing\social-share-kit-1.0.4\dist\js\social-share-kit.min.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\slideshow\icons.html">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\slideshow\icons.html</Link>
</BundleResource>
@@ -1618,23 +1701,35 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\slideshow\style.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\slideshow\style.css</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\toast\toast.js">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\toast\toast.js</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\da.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\da.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\en-US.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\en-US.json</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fastclick\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\fastclick\.bower.json</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\es-MX.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\es-MX.json</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fastclick\LICENSE">
- <Link>Resources\dashboard-ui\bower_components\fastclick\LICENSE</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\kk.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\kk.json</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fastclick\README.md">
- <Link>Resources\dashboard-ui\bower_components\fastclick\README.md</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\nb.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\nb.json</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fastclick\bower.json">
- <Link>Resources\dashboard-ui\bower_components\fastclick\bower.json</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\nl.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\nl.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\strings\ru.json">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\strings\ru.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\toast\toast.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\toast\toast.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fastclick\lib\fastclick.js">
- <Link>Resources\dashboard-ui\bower_components\fastclick\lib\fastclick.js</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\viewmanager\viewcontainer-lite.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\viewmanager\viewcontainer-lite.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\viewmanager\viewmanager.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\viewmanager\viewmanager.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fetch\.bower.json">
<Link>Resources\dashboard-ui\bower_components\fetch\.bower.json</Link>
@@ -1648,6 +1743,78 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fetch\fetch.js">
<Link>Resources\dashboard-ui\bower_components\fetch\fetch.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\CONTRIBUTING.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\FAQ.md">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\FAQ.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\README.md">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\bower.json">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\fingerprint2.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\fingerprint2.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\gulpfile.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\gulpfile.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\index.html">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\package.json">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\package.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\dist\fingerprint2.min.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\dist\fingerprint2.min.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\flash\FontList.as">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\flash\FontList.as</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\flash\Makefile">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\flash\Makefile</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\flash\compiled\FontList.swf">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\flash\compiled\FontList.swf</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\phantomjs-testrunner.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\phantomjs-testrunner.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\phantomjs.runner.sh">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\phantomjs.runner.sh</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\spec_runner.html">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\spec_runner.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\specs.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\specs.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\boot.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\boot.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine-html.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine-html.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine-matchers.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine-matchers.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine.css">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine_favicon.png">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\jasmine_favicon.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\terminal.js">
+ <Link>Resources\dashboard-ui\bower_components\fingerprintjs2\specs\lib\jasmine-2.3.4\terminal.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\font-roboto\.bower.json">
<Link>Resources\dashboard-ui\bower_components\font-roboto\.bower.json</Link>
</BundleResource>
@@ -1687,6 +1854,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\hammerjs\hammer.min.js">
<Link>Resources\dashboard-ui\bower_components\hammerjs\hammer.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\hammerjs\hammer.min.js.map">
+ <Link>Resources\dashboard-ui\bower_components\hammerjs\hammer.min.js.map</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\hammerjs\hammer.min.map">
<Link>Resources\dashboard-ui\bower_components\hammerjs\hammer.min.map</Link>
</BundleResource>
@@ -2059,6 +2229,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-behaviors\iron-control-state.html">
<Link>Resources\dashboard-ui\bower_components\iron-behaviors\iron-control-state.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-behaviors\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-behaviors\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-behaviors\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-behaviors\demo\index.html</Link>
</BundleResource>
@@ -2194,93 +2367,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\test\index.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\README.md">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\iron-dropdown-scroll-manager.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\iron-dropdown-scroll-manager.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\iron-dropdown.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\iron-dropdown.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\demo\grow-height-animation.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\demo\grow-height-animation.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\demo\x-select.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\demo\x-select.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\test\iron-dropdown-scroll-manager.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\test\iron-dropdown-scroll-manager.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\test\iron-dropdown.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\test\iron-dropdown.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-dropdown\test\x-scrollable-element.html">
- <Link>Resources\dashboard-ui\bower_components\iron-dropdown\test\x-scrollable-element.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\README.md">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\iron-fit-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\iron-fit-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\demo\simple-fit.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\demo\simple-fit.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\test\iron-fit-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\test\iron-fit-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-fit-behavior\test\test-fit.html">
- <Link>Resources\dashboard-ui\bower_components\iron-fit-behavior\test\test-fit.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-flex-layout\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-flex-layout\.bower.json</Link>
</BundleResource>
@@ -2554,6 +2640,105 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\test\letters-only.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\test\letters-only.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\.gitignore">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\.gitignore</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\.travis.yml">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\.travis.yml</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\CONTRIBUTING.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\README.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\iron-list.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\iron-list.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\basic.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\basic.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\collapse.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\collapse.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\grid.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\grid.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\scroll-threshold.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\scroll-threshold.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\selection.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\selection.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\demo\data\contacts.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\demo\data\contacts.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\basic.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\basic.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\different-heights.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\different-heights.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\dynamic-item-size.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\dynamic-item-size.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\focus.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\focus.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\grid.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\grid.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\helpers.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\helpers.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\hidden-list.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\hidden-list.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\mutations.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\mutations.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\physical-count.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\physical-count.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\selection.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\selection.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\x-grid.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\x-grid.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\x-list.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\x-list.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\smoke\avg-worst-case.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\smoke\avg-worst-case.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\smoke\dummy-data.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\smoke\dummy-data.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\smoke\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\smoke\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-list\test\smoke\physical-count.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-list\test\smoke\physical-count.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-location\.bower.json</Link>
</BundleResource>
@@ -2608,6 +2793,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\iron-query-params.html">
<Link>Resources\dashboard-ui\bower_components\iron-location\test\iron-query-params.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\redirection.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\redirection.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-media-query\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-media-query\.bower.json</Link>
</BundleResource>
@@ -2737,66 +2925,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\test\iron-meta.html">
<Link>Resources\dashboard-ui\bower_components\iron-meta\test\iron-meta.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\README.md">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\bower.json">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-backdrop.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-backdrop.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-manager.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\iron-overlay-manager.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\.github\ISSUE_TEMPLATE.md">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\.github\ISSUE_TEMPLATE.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\demo\simple-overlay.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\demo\simple-overlay.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\iron-overlay-backdrop.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\iron-overlay-backdrop.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\iron-overlay-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\iron-overlay-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\test-buttons.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\test-buttons.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\test-menu-button.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\test-menu-button.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\test-overlay.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\test-overlay.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-overlay-behavior\test\test-overlay2.html">
- <Link>Resources\dashboard-ui\bower_components\iron-overlay-behavior\test\test-overlay2.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-pages\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-pages\.bower.json</Link>
</BundleResource>
@@ -2908,6 +3036,93 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-resizable-behavior\test\test-elements.html">
<Link>Resources\dashboard-ui\bower_components\iron-resizable-behavior\test\test-elements.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\.gitignore">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\.gitignore</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\.travis.yml">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\.travis.yml</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\CONTRIBUTING.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\README.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\iron-scroll-target-behavior.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\iron-scroll-target-behavior.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\document.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\document.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\scrolling-region.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\scrolling-region.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\x-scrollable.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\demo\x-scrollable.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\test\basic.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\test\basic.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\test\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\test\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\test\x-nested-scrollable.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\test\x-nested-scrollable.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-target-behavior\test\x-scrollable.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-target-behavior\test\x-scrollable.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\.gitignore">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\.gitignore</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\CONTRIBUTING.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\README.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\iron-scroll-threshold.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\iron-scroll-threshold.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\demo\document.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\demo\document.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\demo\sample-content.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\demo\sample-content.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\demo\scrolling-region-decoupled.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\demo\scrolling-region-decoupled.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\demo\scrolling-region.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\demo\scrolling-region.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\test\basic.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\test\basic.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-scroll-threshold\test\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-scroll-threshold\test\index.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-selector\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-selector\.bower.json</Link>
</BundleResource>
@@ -2992,6 +3207,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\.gitignore">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\.gitignore</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\.travis.yml">
+ <Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\.travis.yml</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\CONTRIBUTING.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\README.md">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\README.md</Link>
</BundleResource>
@@ -3004,6 +3225,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\iron-validatable-behavior.html">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\iron-validatable-behavior.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\demo\cats-only.html">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\demo\cats-only.html</Link>
</BundleResource>
@@ -3013,6 +3237,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\demo\validatable-input.html">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\demo\validatable-input.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\test\cats-only.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\test\cats-only.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\test\dogs-only.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\test\dogs-only.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\test\index.html</Link>
</BundleResource>
@@ -4426,6 +4656,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\test\index.html">
<Link>Resources\dashboard-ui\bower_components\neon-animation\test\index.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages-descendant-selection.html">
+ <Link>Resources\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages-descendant-selection.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages-lazy.html">
<Link>Resources\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages-lazy.html</Link>
</BundleResource>
@@ -4570,126 +4803,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-checkbox\test\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-checkbox\test\index.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\README.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\hero.svg">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\hero.svg</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\paper-dialog.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\paper-dialog.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog\test\paper-dialog.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog\test\paper-dialog.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\README.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\hero.svg">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\hero.svg</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-common.css">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-common.css</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-shared-styles.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\paper-dialog-shared-styles.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\.github\ISSUE_TEMPLATE.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\.github\ISSUE_TEMPLATE.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\demo\simple-dialog.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\demo\simple-dialog.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\test\paper-dialog-behavior.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\test\paper-dialog-behavior.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\test\test-buttons.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\test\test-buttons.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-behavior\test\test-dialog.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-behavior\test\test-dialog.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\README.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\hero.svg">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\hero.svg</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\paper-dialog-scrollable.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\paper-dialog-scrollable.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dialog-scrollable\test\paper-dialog-scrollable.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dialog-scrollable\test\paper-dialog-scrollable.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-drawer-panel\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-drawer-panel\.bower.json</Link>
</BundleResource>
@@ -4732,33 +4845,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-drawer-panel\test\small-devices.html">
<Link>Resources\dashboard-ui\bower_components\paper-drawer-panel\test\small-devices.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\README.md">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\paper-dropdown-menu.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\paper-dropdown-menu.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-dropdown-menu\test\paper-dropdown-menu.html">
- <Link>Resources\dashboard-ui\bower_components\paper-dropdown-menu\test\paper-dropdown-menu.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-fab\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-fab\.bower.json</Link>
</BundleResource>
@@ -4810,12 +4896,21 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-icon-button\index.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\paper-icon-button-light.html">
+ <Link>Resources\dashboard-ui\bower_components\paper-icon-button\paper-icon-button-light.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\paper-icon-button.html">
<Link>Resources\dashboard-ui\bower_components\paper-icon-button\paper-icon-button.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\paper-icon-button\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-icon-button\demo\index.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\demo\paper-icon-button-light.html">
+ <Link>Resources\dashboard-ui\bower_components\paper-icon-button\demo\paper-icon-button-light.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\test\a11y.html">
<Link>Resources\dashboard-ui\bower_components\paper-icon-button\test\a11y.html</Link>
</BundleResource>
@@ -5023,48 +5118,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu\test\paper-menu.html">
<Link>Resources\dashboard-ui\bower_components\paper-menu\test\paper-menu.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\.gitignore">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\.gitignore</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\.travis.yml">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\.travis.yml</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\CONTRIBUTING.md">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\CONTRIBUTING.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\README.md">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\bower.json">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\hero.svg">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\hero.svg</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\paper-menu-button-animations.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\paper-menu-button-animations.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\paper-menu-button.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\paper-menu-button.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\.github\ISSUE_TEMPLATE.md">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\.github\ISSUE_TEMPLATE.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\demo\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\demo\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-menu-button\test\paper-menu-button.html">
- <Link>Resources\dashboard-ui\bower_components\paper-menu-button\test\paper-menu-button.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-progress\.bower.json</Link>
</BundleResource>
@@ -5584,6 +5637,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-brainfuck.min.js">
<Link>Resources\dashboard-ui\bower_components\prism\components\prism-brainfuck.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-bro.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\components\prism-bro.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-bro.min.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\components\prism-bro.min.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-c.js">
<Link>Resources\dashboard-ui\bower_components\prism\components\prism-c.js</Link>
</BundleResource>
@@ -5992,6 +6051,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-prolog.min.js">
<Link>Resources\dashboard-ui\bower_components\prism\components\prism-prolog.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-protobuf.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\components\prism-protobuf.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-protobuf.min.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\components\prism-protobuf.min.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\components\prism-puppet.js">
<Link>Resources\dashboard-ui\bower_components\prism\components\prism-puppet.js</Link>
</BundleResource>
@@ -6247,6 +6312,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\line-numbers\prism-line-numbers.min.js">
<Link>Resources\dashboard-ui\bower_components\prism\plugins\line-numbers\prism-line-numbers.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\normalize-whitespace\prism-normalize-whitespace.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\plugins\normalize-whitespace\prism-normalize-whitespace.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\normalize-whitespace\prism-normalize-whitespace.min.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\plugins\normalize-whitespace\prism-normalize-whitespace.min.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\previewer-angle\prism-previewer-angle.css">
<Link>Resources\dashboard-ui\bower_components\prism\plugins\previewer-angle\prism-previewer-angle.css</Link>
</BundleResource>
@@ -6325,6 +6396,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\show-language\prism-show-language.min.js">
<Link>Resources\dashboard-ui\bower_components\prism\plugins\show-language\prism-show-language.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.css">
+ <Link>Resources\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.min.js">
+ <Link>Resources\dashboard-ui\bower_components\prism\plugins\unescaped-markup\prism-unescaped-markup.min.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\wpd\prism-wpd.css">
<Link>Resources\dashboard-ui\bower_components\prism\plugins\wpd\prism-wpd.css</Link>
</BundleResource>
@@ -6334,2445 +6414,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\plugins\wpd\prism-wpd.min.js">
<Link>Resources\dashboard-ui\bower_components\prism\plugins\wpd\prism-wpd.min.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\run-child.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\run-child.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\run.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\run.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\testrunner-tests.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\testrunner-tests.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\helper\components.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\helper\components.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\helper\prism-loader.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\helper\prism-loader.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\helper\test-case.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\helper\test-case.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\helper\test-discovery.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\helper\test-discovery.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\helper\token-stream-transformer.js">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\helper\token-stream-transformer.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\eol-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\eol-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\string-template_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\string-template_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\abap\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\abap\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\actionscript\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\actionscript\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\actionscript\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\actionscript\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-flags_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-flags_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-inline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\directive-inline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apacheconf\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apacheconf\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\assignment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\assignment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\dfn_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\dfn_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\dyadic-operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\dyadic-operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\monadic-operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\monadic-operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\statement_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\statement_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\apl\system-function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\apl\system-function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\class_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\class_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\applescript\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\applescript\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\admonition_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\admonition_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\attribute-entry_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\attribute-entry_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\attributes_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\attributes_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\callout_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\callout_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\comment-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\comment-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\entity_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\entity_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\hr_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\hr_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\indented-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\indented-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\inline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\inline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\line-continuation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\line-continuation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\list-label_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\list-label_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\list-punctuation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\list-punctuation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\literal-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\literal-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\macro_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\macro_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\other-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\other-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\page-break_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\page-break_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\passthrough-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\passthrough-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\replacement_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\replacement_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\table_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\table_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\asciidoc\title_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\asciidoc\title_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\aspnet\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\aspnet\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\aspnet\page-directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\aspnet\page-directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autohotkey\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autohotkey\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\autoit\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\autoit\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\arithmetic_environment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\arithmetic_environment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\command_substitution_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\command_substitution_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\shebang_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\shebang_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bash\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bash\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\basic\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\basic\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\batch\command_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\batch\command_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\batch\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\batch\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\batch\label_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\batch\label_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\c_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\c_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\bison\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\bison\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\brainfuck\all_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\brainfuck\all_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\c\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\c\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\c\macro_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\c\macro_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\c\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\c\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\c\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\c\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\c+pure\c_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\c+pure\c_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\class-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\class-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\clike\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\clike\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\block-regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\block-regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\class-member_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\class-member_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\inline-javascript_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\inline-javascript_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript+haml\coffeescript_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript+haml\coffeescript_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\coffeescript+jade\coffeescript_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\coffeescript+jade\coffeescript_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\cpp\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\cpp\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\cpp\class-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\cpp\class-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\cpp\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\cpp\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\cpp+pure\cpp_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\cpp+pure\cpp_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\crystal\attribute_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\crystal\attribute_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\crystal\expansion_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\crystal\expansion_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\crystal\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\crystal\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\crystal\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\crystal\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp\issue806.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp\issue806.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp\preprocessor_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp\preprocessor_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\csharp+aspnet\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\csharp+aspnet\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\entity_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\entity_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\hexcode_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\hexcode_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css!+css-extras\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css+haml\css+haml_usage.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css+haml\css+haml_usage.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\css+textile\css_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\css+textile\css_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\register_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\register_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\d\token-string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\d\token-string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\dart\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\dart\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\dart\metadata_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\dart\metadata_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\dart\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\dart\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\dart\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\dart\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\diff\coord_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\diff\coord_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\diff\diff_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\diff\diff_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\docker\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\docker\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\docker\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\docker\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\docker\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\docker\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\char_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\char_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\eiffel\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\eiffel\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\atom_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\atom_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\attr-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\attr-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\attribute_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\attribute_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\capture_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\capture_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\issue775.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\issue775.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\elixir\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\elixir\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\atom_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\atom_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\erlang\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\erlang\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fortran+pure\fortran_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fortran+pure\fortran_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fsharp\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fsharp\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fsharp\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fsharp\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fsharp\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fsharp\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fsharp\preprocessor_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fsharp\preprocessor_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\fsharp\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\fsharp\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\feature_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\feature_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\outline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\outline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\pystring_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\pystring_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\scenario_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\scenario_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\table_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\table_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\gherkin\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\gherkin\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\command_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\command_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\commit_sha1_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\commit_sha1_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\coord_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\coord_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\diff_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\diff_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\git\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\git\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\glsl\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\glsl\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\glsl\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\glsl\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\glsl\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\glsl\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\glsl\preprocessor_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\glsl\preprocessor_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\go\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\go\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\annotation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\annotation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\shebang_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\shebang_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\spock-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\spock-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\groovy\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\groovy\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\code_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\code_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\doctype_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\doctype_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\interpolation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\interpolation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\multiline-code_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\multiline-code_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\multiline-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\multiline-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haml\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haml\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars\block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars\block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\handlebars+jade\handlebars_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\handlebars+jade\handlebars_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\char_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\char_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\hvariable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\hvariable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\import_statement_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\import_statement_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haskell\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haskell\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\metadata_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\metadata_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\preprocessor_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\preprocessor_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\reification_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\reification_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\haxe\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\haxe\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\http\header-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\http\header-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\http\request-line_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\http\request-line_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\http\response-status_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\http\response-status_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\builtin-keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\builtin-keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\icon\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\icon\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\position_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\position_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\title_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\title_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\inform7\verb_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\inform7\verb_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ini\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ini\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ini\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ini\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ini\key_value_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ini\key_value_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\adverb_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\adverb_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\conjunction_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\conjunction_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\j\verb_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\j\verb_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\code_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\code_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\doctype_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\doctype_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\flow-control_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\flow-control_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\mixin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\mixin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\multiline-plain-text_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\multiline-plain-text_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\multiline-script_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\multiline-script_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\plain-text_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\plain-text_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\script_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\script_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jade\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jade\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\java\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\java\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\java\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\java\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\java\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\java\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript\template-string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript\template-string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript+haml\javascript_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript+haml\javascript_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\javascript+http\javascript_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\javascript+http\javascript_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\jsx\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\jsx\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\julia\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\julia\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\bold_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\bold_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\keyman\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\keyman\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\annotation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\annotation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\interpolation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\interpolation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\label_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\label_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\kotlin\raw-string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\kotlin\raw-string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\cdata_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\cdata_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\equation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\equation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\headline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\headline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\latex\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\latex\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less+haml\less_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less+haml\less_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\less+jade\less_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\less+jade\less_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\label_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\label_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lolcode\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lolcode\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\lua\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\lua\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\makefile\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\makefile\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\blockquote_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\blockquote_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\bold_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\bold_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\code_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\code_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\hr_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\hr_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\italic_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\italic_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\list_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\list_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\title_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\title_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\url-reference_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\url-reference_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown+haml\markdown_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown+haml\markdown_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markdown+jade\markdown_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markdown+jade\markdown_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\cdata_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\cdata_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\doctype_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\doctype_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\entity_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\entity_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\issue585.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\issue585.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\prolog_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\prolog_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\tag_attribute_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\tag_attribute_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup\tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup!+css\css_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup!+css\css_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup!+javascript\javascript_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup!+javascript\javascript_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+actionscript\xml_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+actionscript\xml_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+css+wiki\table-tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+css+wiki\table-tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+haml\markup_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+haml\markup_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+http\markup_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+http\markup_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+jade\markup_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+jade\markup_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+javascript+csharp+aspnet\script_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+javascript+csharp+aspnet\script_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\markup+php\markup_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\markup+php\markup_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\matlab\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\matlab\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\code_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\code_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\flag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\flag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mel\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mel\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\parameter_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\parameter_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\mizar\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\mizar\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\preprocessor_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\preprocessor_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\monkey\type-char_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\monkey\type-char_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\label_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\label_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\register_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\register_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nasm\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nasm\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nginx\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nginx\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nginx\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nginx\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nginx\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nginx\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nim\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nim\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\antiquotation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\antiquotation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nix\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nix\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\nsis\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\nsis\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\objectivec\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\objectivec\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\objectivec\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\objectivec\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\objectivec\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\objectivec\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ocaml\type_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ocaml\type_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\atom_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\atom_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\attr-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\attr-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\oz\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\oz\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parigp\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parigp\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\escape_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\escape_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\expression_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\expression_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\parser-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\parser-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\parser\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\parser\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pascal\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pascal\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pascal\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pascal\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pascal\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pascal\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pascal\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pascal\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pascal\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pascal\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\filehandle_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\filehandle_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\perl\vstring_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\perl\vstring_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\delimiter_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\delimiter_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\package_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\package_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\shell-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\shell-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\global_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\global_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\scope_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\scope_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\this_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\php!+php-extras\this_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\namespace_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\namespace_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\powershell\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\powershell\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\processing\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\processing\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\processing\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\processing\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\processing\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\processing\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\processing\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\processing\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\processing\type_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\processing\type_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\prolog\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\prolog\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\attr-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\attr-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\datatype_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\datatype_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\heredoc_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\heredoc_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\interpolation_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\interpolation_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\puppet\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\puppet\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\special_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\special_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\pure\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\pure\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\class-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\class-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\python\triple-quoted-string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\python\triple-quoted-string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\adverb_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\adverb_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\datetime_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\datetime_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\q\verb_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\q\verb_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\qore\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\qore\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\ellipsis_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\ellipsis_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\percent-operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\percent-operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\r\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\r\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\command-line-option_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\command-line-option_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\doctest-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\doctest-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\field_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\field_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\hr_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\hr_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\inline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\inline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\link-target_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\link-target_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\link_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\link_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\list-bullet_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\list-bullet_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\literal-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\literal-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\quoted-literal-block_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\quoted-literal-block_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\substitution-def_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\substitution-def_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\table_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\table_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rest\title_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rest\title_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\character_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\character_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\date_time_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\date_time_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\reference_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\reference_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rip\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rip\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\component_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\component_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\optional_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\optional_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\value_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\value_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\roboconf\wildcard_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\roboconf\wildcard_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\regex_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\regex_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\ruby\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\ruby\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\attribute_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\attribute_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\closure-params_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\closure-params_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\macro-rules_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\macro-rules_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\rust\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\rust\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\datalines_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\datalines_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\datetime_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\datetime_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sas\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sas\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sass\atrule-line_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sass\atrule-line_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sass\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sass\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sass\property-line_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sass\property-line_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sass\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sass\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\sass\variable-line_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\sass\variable-line_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scala\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scala\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scala\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scala\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scala\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scala\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scala\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scala\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scala\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scala\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scheme\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scheme\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\null_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\null_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\placeholder_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\placeholder_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\statement_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\statement_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss+haml\scss_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss+haml\scss_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\scss+jade\scss_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\scss+jade\scss_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\block-arguments_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\block-arguments_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\character_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\character_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smalltalk\temporary-variables_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smalltalk\temporary-variables_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\attr-name_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\attr-name_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\smarty-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\smarty-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\smarty\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\smarty\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\atrule-declaration_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\atrule-declaration_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\func_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\func_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\hexcode_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\hexcode_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\property-declaration_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\property-declaration_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\selector_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\selector_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus\variable-declaration_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus\variable-declaration_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\stylus+jade\stylus_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\stylus+jade\stylus_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\atrule_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\atrule_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\swift\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\swift\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\scope_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\scope_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\tcl\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\tcl\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\acronym_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\acronym_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\block-tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\block-tag_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\footnote_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\footnote_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\image_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\image_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\inline_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\inline_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\link-ref_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\link-ref_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\link_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\link_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\list_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\list_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\mark_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\mark_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\textile\table_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\textile\table_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\twig+jade\twig_inclusion.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\twig+jade\twig_inclusion.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\typescript\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\typescript\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\property_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\property_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\verilog\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\verilog\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\constant_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\constant_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vhdl\vhdl-vectors_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vhdl\vhdl-vectors_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\builtin_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\builtin_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\function_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\function_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\keyword_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\keyword_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\operator_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\operator_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\vim\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\vim\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\block-comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\block-comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\emphasis_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\emphasis_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\heading_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\heading_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\hr_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\hr_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\nowiki_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\nowiki_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\symbol_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\symbol_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\url_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\url_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\wiki\variable_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\wiki\variable_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\boolean_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\boolean_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\comment_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\comment_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\datetime_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\datetime_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\directive_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\directive_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\important_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\important_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\key_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\key_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\null_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\null_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\number_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\number_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\scalar_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\scalar_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\string_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\string_feature.test</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\tests\languages\yaml\tag_feature.test">
- <Link>Resources\dashboard-ui\bower_components\prism\tests\languages\yaml\tag_feature.test</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\prism\themes\prism-coy.css">
<Link>Resources\dashboard-ui\bower_components\prism\themes\prism-coy.css</Link>
</BundleResource>
@@ -8878,51 +6519,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\requirejs\require.js">
<Link>Resources\dashboard-ui\bower_components\requirejs\require.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\.bower.json">
- <Link>Resources\dashboard-ui\bower_components\velocity\.bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\bower.json">
- <Link>Resources\dashboard-ui\bower_components\velocity\bower.json</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\velocity.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\velocity.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\velocity.min.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\velocity.min.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\velocity.ui.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\velocity.ui.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\velocity.ui.min.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\velocity.ui.min.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\bluebird.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\bluebird.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\index.html">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\index.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\jquery-1.11.1.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\jquery-1.11.1.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\jquery-1.4.3.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\jquery-1.4.3.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\q.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\q.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\qunit-1.14.0.css">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\qunit-1.14.0.css</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\qunit-1.14.0.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\qunit-1.14.0.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\when.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\when.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\velocity\test\zepto.js">
- <Link>Resources\dashboard-ui\bower_components\velocity\test\zepto.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\web-animations-js\.bower.json">
<Link>Resources\dashboard-ui\bower_components\web-animations-js\.bower.json</Link>
</BundleResource>
@@ -9007,15 +6603,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\webcomponentsjs\webcomponents.min.js">
<Link>Resources\dashboard-ui\bower_components\webcomponentsjs\webcomponents.min.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\apphost.js">
+ <Link>Resources\dashboard-ui\components\apphost.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\chromecasthelpers.js">
<Link>Resources\dashboard-ui\components\chromecasthelpers.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\favoriteitems.js">
<Link>Resources\dashboard-ui\components\favoriteitems.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\filedownloader.js">
- <Link>Resources\dashboard-ui\components\filedownloader.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\humanedate.js">
<Link>Resources\dashboard-ui\components\humanedate.js</Link>
</BundleResource>
@@ -9025,11 +6621,8 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\remotecontrolautoplay.js">
<Link>Resources\dashboard-ui\components\remotecontrolautoplay.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\servertestermessage.js">
- <Link>Resources\dashboard-ui\components\servertestermessage.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\sharingwidget.js">
- <Link>Resources\dashboard-ui\components\sharingwidget.js</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\scrollthreshold.js">
+ <Link>Resources\dashboard-ui\components\scrollthreshold.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\viewcontainer-lite.js">
<Link>Resources\dashboard-ui\components\viewcontainer-lite.js</Link>
@@ -9079,6 +6672,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\imageuploader\imageuploader.template.html">
<Link>Resources\dashboard-ui\components\imageuploader\imageuploader.template.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\ironcardlist\ironcardlist.js">
+ <Link>Resources\dashboard-ui\components\ironcardlist\ironcardlist.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\ironcardlist\ironcardlist.template.html">
+ <Link>Resources\dashboard-ui\components\ironcardlist\ironcardlist.template.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\itemidentifier\itemidentifier.js">
<Link>Resources\dashboard-ui\components\itemidentifier\itemidentifier.js</Link>
</BundleResource>
@@ -9112,24 +6711,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\playlisteditor\playlisteditor.js">
<Link>Resources\dashboard-ui\components\playlisteditor\playlisteditor.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\recordingcreator\recordingcreator.js">
- <Link>Resources\dashboard-ui\components\recordingcreator\recordingcreator.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\recordingcreator\recordingcreator.template.html">
- <Link>Resources\dashboard-ui\components\recordingcreator\recordingcreator.template.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\subtitleeditor\subtitleeditor.js">
<Link>Resources\dashboard-ui\components\subtitleeditor\subtitleeditor.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\subtitleeditor\subtitleeditor.template.html">
<Link>Resources\dashboard-ui\components\subtitleeditor\subtitleeditor.template.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tvguide\tvguide.js">
- <Link>Resources\dashboard-ui\components\tvguide\tvguide.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tvguide\tvguide.template.html">
- <Link>Resources\dashboard-ui\components\tvguide\tvguide.template.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tvproviders\schedulesdirect.js">
<Link>Resources\dashboard-ui\components\tvproviders\schedulesdirect.js</Link>
</BundleResource>
@@ -9289,9 +6876,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\clients\windowsrt.png">
<Link>Resources\dashboard-ui\css\images\clients\windowsrt.png</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\editor\lock.png">
- <Link>Resources\dashboard-ui\css\images\editor\lock.png</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\editor\missing.png">
<Link>Resources\dashboard-ui\css\images\editor\missing.png</Link>
</BundleResource>
@@ -9451,6 +7035,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\userdata\password.png">
<Link>Resources\dashboard-ui\css\images\userdata\password.png</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\polymer\paper-icon-button-light.css">
+ <Link>Resources\dashboard-ui\css\polymer\paper-icon-button-light.css</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\devices\android\android.css">
<Link>Resources\dashboard-ui\devices\android\android.css</Link>
</BundleResource>
@@ -9673,12 +7260,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvsuggested.js">
<Link>Resources\dashboard-ui\scripts\livetvsuggested.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtimer.js">
- <Link>Resources\dashboard-ui\scripts\livetvtimer.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtimers.js">
- <Link>Resources\dashboard-ui\scripts\livetvtimers.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js">
<Link>Resources\dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js</Link>
</BundleResource>
@@ -9859,9 +7440,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\shared.js">
<Link>Resources\dashboard-ui\scripts\shared.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\sharingmanager.js">
- <Link>Resources\dashboard-ui\scripts\sharingmanager.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\site.js">
<Link>Resources\dashboard-ui\scripts\site.js</Link>
</BundleResource>
@@ -9994,6 +7572,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr-CA.json">
<Link>Resources\dashboard-ui\strings\fr-CA.json</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr-FR.json">
+ <Link>Resources\dashboard-ui\strings\fr-FR.json</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr.json">
<Link>Resources\dashboard-ui\strings\fr.json</Link>
</BundleResource>
@@ -10045,6 +7626,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\ru.json">
<Link>Resources\dashboard-ui\strings\ru.json</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\sk.json">
+ <Link>Resources\dashboard-ui\strings\sk.json</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\sl-SI.json">
<Link>Resources\dashboard-ui\strings\sl-SI.json</Link>
</BundleResource>
@@ -10132,15 +7716,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.map">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.map</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.icons.css">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.icons.css</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.js">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.theme.css">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.theme.css</Link>
</BundleResource>
@@ -10159,33 +7737,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jstree\themes\default\throbber.gif">
<Link>Resources\dashboard-ui\thirdparty\jstree\themes\default\throbber.gif</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\LICENSE">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\LICENSE</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\README.md">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\README.md</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\css\social-share-kit.css">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\css\social-share-kit.css</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.eot">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.eot</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.svg">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.svg</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.ttf">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.ttf</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.woff">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.woff</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.js">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.min.js">
- <Link>Resources\dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.min.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\voice\Readme.md">
<Link>Resources\dashboard-ui\voice\Readme.md</Link>
</BundleResource>
diff --git a/MediaBrowser.Server.Mac/Main.cs b/MediaBrowser.Server.Mac/Main.cs
index b7e158c5d..b48f44707 100644
--- a/MediaBrowser.Server.Mac/Main.cs
+++ b/MediaBrowser.Server.Mac/Main.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Server.Mac
var fileSystem = new ManagedFileSystem(new PatternsLogger(logManager.GetLogger("FileSystem")), false, true);
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
- var nativeApp = new NativeApp();
+ var nativeApp = new NativeApp(logManager.GetLogger("App"));
AppHost = new ApplicationHost(appPaths, logManager, options, fileSystem, "Emby.Server.Mac.pkg", nativeApp);
diff --git a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
index 67ad96859..0b2f533a4 100644
--- a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
using System.Diagnostics;
@@ -14,6 +15,13 @@ namespace MediaBrowser.Server.Mac
{
public abstract class BaseMonoApp : INativeApp
{
+ protected ILogger Logger { get; private set; }
+
+ protected BaseMonoApp(ILogger logger)
+ {
+ Logger = logger;
+ }
+
/// <summary>
/// Shutdowns this instance.
/// </summary>
@@ -39,6 +47,21 @@ namespace MediaBrowser.Server.Mac
}
}
+ public void PreventSystemStandby()
+ {
+
+ }
+
+ public void AllowSystemStandby()
+ {
+
+ }
+
+ public IDbConnector GetDbConnector()
+ {
+ return new DbConnector(Logger);
+ }
+
public virtual bool SupportsLibraryMonitor
{
get
@@ -64,11 +87,6 @@ namespace MediaBrowser.Server.Mac
get { return false; }
}
- public void PreventSystemStandby()
- {
-
- }
-
public List<Assembly> GetAssembliesWithParts()
{
var list = new List<Assembly>();
diff --git a/MediaBrowser.Server.Mac/Native/NativeApp.cs b/MediaBrowser.Server.Mac/Native/NativeApp.cs
index 005fb0914..59fa92dd1 100644
--- a/MediaBrowser.Server.Mac/Native/NativeApp.cs
+++ b/MediaBrowser.Server.Mac/Native/NativeApp.cs
@@ -1,5 +1,6 @@
using System;
using MediaBrowser.Server.Startup.Common;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Server.Mac
{
@@ -8,7 +9,12 @@ namespace MediaBrowser.Server.Mac
/// </summary>
public class NativeApp : BaseMonoApp
{
- /// <summary>
+ public NativeApp(ILogger logger)
+ : base(logger)
+ {
+ }
+
+ /// <summary>
/// Shutdowns this instance.
/// </summary>
public override void Shutdown()
diff --git a/MediaBrowser.Server.Mac/Native/SqliteExtensions.cs b/MediaBrowser.Server.Mac/Native/SqliteExtensions.cs
new file mode 100644
index 000000000..a05bb3f26
--- /dev/null
+++ b/MediaBrowser.Server.Mac/Native/SqliteExtensions.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Data;
+using System.Data.SQLite;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.Persistence;
+
+namespace MediaBrowser.Server.Mac
+{
+ /// <summary>
+ /// Class SQLiteExtensions
+ /// </summary>
+ static class SqliteExtensions
+ {
+ /// <summary>
+ /// Connects to db.
+ /// </summary>
+ /// <param name="dbPath">The db path.</param>
+ /// <param name="logger">The logger.</param>
+ /// <returns>Task{IDbConnection}.</returns>
+ /// <exception cref="System.ArgumentNullException">dbPath</exception>
+ public static async Task<IDbConnection> ConnectToDb(string dbPath, ILogger logger)
+ {
+ if (string.IsNullOrEmpty(dbPath))
+ {
+ throw new ArgumentNullException("dbPath");
+ }
+
+ logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath);
+
+ var connectionstr = new SQLiteConnectionStringBuilder
+ {
+ PageSize = 4096,
+ CacheSize = 2000,
+ SyncMode = SynchronizationModes.Full,
+ DataSource = dbPath,
+ JournalMode = SQLiteJournalModeEnum.Wal
+ };
+
+ var connection = new SQLiteConnection(connectionstr.ConnectionString);
+
+ await connection.OpenAsync().ConfigureAwait(false);
+
+ return connection;
+ }
+ }
+
+ public class DbConnector : IDbConnector
+ {
+ private readonly ILogger _logger;
+
+ public DbConnector(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public Task<IDbConnection> Connect(string dbPath)
+ {
+ return SqliteExtensions.ConnectToDb(dbPath, _logger);
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index a012a19a3..5d7274356 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Model.System;
using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem;
@@ -176,7 +177,7 @@ namespace MediaBrowser.Server.Mono.Native
}
else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase))
{
- info.SystemArchitecture = Architecture.X86_X64;
+ info.SystemArchitecture = Architecture.X64;
}
else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase))
{
@@ -260,7 +261,7 @@ namespace MediaBrowser.Server.Mono.Native
switch (environment.SystemArchitecture)
{
- case Architecture.X86_X64:
+ case Architecture.X64:
info.Version = "20160124";
break;
case Architecture.X86:
@@ -283,7 +284,7 @@ namespace MediaBrowser.Server.Mono.Native
switch (environment.SystemArchitecture)
{
- case Architecture.X86_X64:
+ case Architecture.X64:
return new[]
{
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.8.5.7z"
@@ -300,7 +301,7 @@ namespace MediaBrowser.Server.Mono.Native
switch (environment.SystemArchitecture)
{
- case Architecture.X86_X64:
+ case Architecture.X64:
return new[]
{
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-64bit-static.7z"
diff --git a/MediaBrowser.Server.Mono/Native/DbConnector.cs b/MediaBrowser.Server.Mono/Native/DbConnector.cs
index 3230f92f9..5ad3ecfef 100644
--- a/MediaBrowser.Server.Mono/Native/DbConnector.cs
+++ b/MediaBrowser.Server.Mono/Native/DbConnector.cs
@@ -16,9 +16,9 @@ namespace MediaBrowser.Server.Mono.Native
_logger = logger;
}
- public Task<IDbConnection> Connect(string dbPath)
+ public Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null)
{
- return SqliteExtensions.ConnectToDb(dbPath, _logger);
+ return SqliteExtensions.ConnectToDb(dbPath, isReadOnly, enablePooling, cacheSize, _logger);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 75e3bb7f5..ec1ccbff5 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -313,7 +313,6 @@ namespace MediaBrowser.Server.Startup.Common
/// <summary>
/// Runs the startup tasks.
/// </summary>
- /// <returns>Task.</returns>
public override async Task RunStartupTasks()
{
if (ServerConfigurationManager.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion &&
@@ -324,6 +323,8 @@ namespace MediaBrowser.Server.Startup.Common
await base.RunStartupTasks().ConfigureAwait(false);
+ InitMediaEncoder();
+
Logger.Info("ServerId: {0}", SystemId);
Logger.Info("Core startup complete");
HttpServer.GlobalResponse = null;
@@ -345,6 +346,20 @@ namespace MediaBrowser.Server.Startup.Common
LogManager.RemoveConsoleOutput();
}
+ private void InitMediaEncoder()
+ {
+ MediaEncoder.Init();
+
+ Task.Run(() =>
+ {
+ var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(MediaEncoder.EncoderPath);
+
+ var mediaEncoder = (MediaEncoder) MediaEncoder;
+ mediaEncoder.SetAvailableDecoders(result.Item1);
+ mediaEncoder.SetAvailableEncoders(result.Item2);
+ });
+ }
+
public override Task Init(IProgress<double> progress)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
@@ -381,7 +396,9 @@ namespace MediaBrowser.Server.Startup.Common
new OmdbEpisodeProviderMigration(ServerConfigurationManager),
new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
new DbMigration(ServerConfigurationManager, TaskManager),
- new FolderViewSettingMigration(ServerConfigurationManager, UserManager)
+ new FolderViewSettingMigration(ServerConfigurationManager, UserManager),
+ new CollectionGroupingMigration(ServerConfigurationManager, UserManager),
+ new CollectionsViewMigration(ServerConfigurationManager, UserManager)
};
foreach (var task in migrations)
@@ -400,7 +417,6 @@ namespace MediaBrowser.Server.Startup.Common
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
- /// <returns>Task.</returns>
protected override async Task RegisterResources(IProgress<double> progress)
{
await base.RegisterResources(progress).ConfigureAwait(false);
@@ -423,11 +439,11 @@ namespace MediaBrowser.Server.Startup.Common
UserRepository = await GetUserRepository().ConfigureAwait(false);
RegisterSingleInstance(UserRepository);
- var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
+ var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector());
DisplayPreferencesRepository = displayPreferencesRepo;
RegisterSingleInstance(DisplayPreferencesRepository);
- var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager);
+ var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector());
ItemRepository = itemRepo;
RegisterSingleInstance(ItemRepository);
@@ -552,8 +568,8 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance(NativeApp.GetPowerManagement());
- var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
- await sharingRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ var sharingRepo = new SharingRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+ await sharingRepo.Initialize().ConfigureAwait(false);
RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
RegisterSingleInstance<ISsdpHandler>(new SsdpHandler(LogManager.GetLogger("SsdpHandler"), ServerConfigurationManager, this));
@@ -570,9 +586,12 @@ namespace MediaBrowser.Server.Startup.Common
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager);
RegisterSingleInstance(SubtitleEncoder);
- await displayPreferencesRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
- await ConfigureUserDataRepositories().ConfigureAwait(false);
- await itemRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await displayPreferencesRepo.Initialize().ConfigureAwait(false);
+
+ var userDataRepo = new SqliteUserDataRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
+
+ ((UserDataManager)UserDataManager).Repository = userDataRepo;
+ await itemRepo.Initialize(userDataRepo).ConfigureAwait(false);
((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
await ConfigureNotificationsRepository().ConfigureAwait(false);
progress.Report(100);
@@ -631,14 +650,21 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task.</returns>
private async Task RegisterMediaEncoder(IProgress<double> progress)
{
- var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetType().Assembly, NativeApp.GetFfmpegInstallInfo())
+ string encoderPath = null;
+ string probePath = null;
+
+ var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetFfmpegInstallInfo())
.GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false);
+ encoderPath = info.EncoderPath;
+ probePath = info.ProbePath;
+ _hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
+
var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
JsonSerializer,
- info.EncoderPath,
- info.ProbePath,
- info.Version,
+ encoderPath,
+ probePath,
+ _hasExternalEncoder,
ServerConfigurationManager,
FileSystemManager,
LiveTvManager,
@@ -651,14 +677,6 @@ namespace MediaBrowser.Server.Startup.Common
MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder);
-
- Task.Run(() =>
- {
- var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(info);
-
- mediaEncoder.SetAvailableDecoders(result.Item1);
- mediaEncoder.SetAvailableEncoders(result.Item2);
- });
}
/// <summary>
@@ -669,9 +687,9 @@ namespace MediaBrowser.Server.Startup.Common
{
try
{
- var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
+ var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
@@ -688,36 +706,36 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>Task{IUserRepository}.</returns>
private async Task<IFileOrganizationRepository> GetFileOrganizationRepository()
{
- var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<IAuthenticationRepository> GetAuthenticationRepository()
{
- var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<IActivityRepository> GetActivityLogRepository()
{
- var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
+ var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
private async Task<ISyncRepository> GetSyncRepository()
{
- var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths);
+ var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
return repo;
}
@@ -725,12 +743,11 @@ namespace MediaBrowser.Server.Startup.Common
/// <summary>
/// Configures the repositories.
/// </summary>
- /// <returns>Task.</returns>
private async Task ConfigureNotificationsRepository()
{
- var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths);
+ var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector());
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await repo.Initialize().ConfigureAwait(false);
NotificationsRepository = repo;
@@ -738,19 +755,6 @@ namespace MediaBrowser.Server.Startup.Common
}
/// <summary>
- /// Configures the user data repositories.
- /// </summary>
- /// <returns>Task.</returns>
- private async Task ConfigureUserDataRepositories()
- {
- var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
-
- await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
-
- ((UserDataManager)UserDataManager).Repository = repo;
- }
-
- /// <summary>
/// Dirty hacks
/// </summary>
private void SetStaticProperties()
@@ -831,19 +835,57 @@ namespace MediaBrowser.Server.Startup.Common
private string CertificatePath { get; set; }
+ private string NormalizeConfiguredLocalAddress(string address)
+ {
+ var index = address.Trim('/').IndexOf('/');
+
+ if (index != -1)
+ {
+ address = address.Substring(index + 1);
+ }
+
+ return address.Trim('/');
+ }
private IEnumerable<string> GetUrlPrefixes()
{
- var prefixes = new List<string>
- {
- "http://+:" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/"
- };
+ var hosts = ServerConfigurationManager
+ .Configuration
+ .LocalNetworkAddresses
+ .Select(NormalizeConfiguredLocalAddress)
+ .ToList();
+
+ if (hosts.Count == 0)
+ {
+ hosts.Add("+");
+ }
- if (!string.IsNullOrWhiteSpace(CertificatePath))
+ if (!hosts.Contains("+", StringComparer.OrdinalIgnoreCase))
{
- prefixes.Add("https://+:" + ServerConfigurationManager.Configuration.HttpsPortNumber + "/");
+ if (!hosts.Contains("localhost", StringComparer.OrdinalIgnoreCase))
+ {
+ hosts.Add("localhost");
+ }
+
+ if (!hosts.Contains("127.0.0.1", StringComparer.OrdinalIgnoreCase))
+ {
+ hosts.Add("127.0.0.1");
+ }
}
- return prefixes;
+ return hosts.SelectMany(i =>
+ {
+ var prefixes = new List<string>
+ {
+ "http://"+i+":" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/"
+ };
+
+ if (!string.IsNullOrWhiteSpace(CertificatePath))
+ {
+ prefixes.Add("https://" + i + ":" + ServerConfigurationManager.Configuration.HttpsPortNumber + "/");
+ }
+
+ return prefixes;
+ });
}
/// <summary>
@@ -1058,12 +1100,15 @@ namespace MediaBrowser.Server.Startup.Common
}
}
+ private bool _hasExternalEncoder;
/// <summary>
/// Gets the system status.
/// </summary>
/// <returns>SystemInfo.</returns>
- public virtual SystemInfo GetSystemInfo()
+ public async Task<SystemInfo> GetSystemInfo()
{
+ var localAddress = await GetLocalApiUrl().ConfigureAwait(false);
+
return new SystemInfo
{
HasPendingRestart = HasPendingRestart,
@@ -1094,8 +1139,10 @@ namespace MediaBrowser.Server.Startup.Common
IsRunningAsService = IsRunningAsService,
SupportsRunningAsService = SupportsRunningAsService,
ServerName = FriendlyName,
- LocalAddress = LocalApiUrl,
- SupportsLibraryMonitor = SupportsLibraryMonitor
+ LocalAddress = localAddress,
+ SupportsLibraryMonitor = SupportsLibraryMonitor,
+ HasExternalEncoder = _hasExternalEncoder,
+ SystemArchitecture = NativeApp.Environment.SystemArchitecture
};
}
@@ -1112,29 +1159,26 @@ namespace MediaBrowser.Server.Startup.Common
get { return !string.IsNullOrWhiteSpace(HttpServer.CertificatePath); }
}
- public string LocalApiUrl
+ public async Task<string> GetLocalApiUrl()
{
- get
+ try
{
- try
- {
- // Return the first matched address, if found, or the first known local address
- var address = LocalIpAddresses.FirstOrDefault(i => !IPAddress.IsLoopback(i));
-
- if (address != null)
- {
- return GetLocalApiUrl(address);
- }
+ // Return the first matched address, if found, or the first known local address
+ var address = (await GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !IPAddress.IsLoopback(i));
- return null;
- }
- catch (Exception ex)
+ if (address != null)
{
- Logger.ErrorException("Error getting local Ip address information", ex);
+ return GetLocalApiUrl(address);
}
return null;
}
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error getting local Ip address information", ex);
+ }
+
+ return null;
}
public string GetLocalApiUrl(IPAddress ipAddress)
@@ -1154,16 +1198,13 @@ namespace MediaBrowser.Server.Startup.Common
HttpPort.ToString(CultureInfo.InvariantCulture));
}
- public List<IPAddress> LocalIpAddresses
+ public async Task<List<IPAddress>> GetLocalIpAddresses()
{
- get
- {
- var localAddresses = NetworkManager.GetLocalIpAddresses()
- .Where(IsIpAddressValid)
- .ToList();
+ var localAddresses = NetworkManager.GetLocalIpAddresses()
+ .Where(IsIpAddressValid)
+ .ToList();
- return localAddresses;
- }
+ return localAddresses;
}
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
@@ -1349,7 +1390,6 @@ namespace MediaBrowser.Server.Startup.Common
/// <param name="package">The package that contains the update</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress)
{
await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegInstallInfo.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegInstallInfo.cs
index 1ce1b55c2..a2a44f805 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegInstallInfo.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegInstallInfo.cs
@@ -8,7 +8,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
public string FFProbeFilename { get; set; }
public string ArchiveType { get; set; }
public string[] DownloadUrls { get; set; }
- public bool IsEmbedded { get; set; }
public FFMpegInstallInfo()
{
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs
index ee284fdc5..a4c50d0d8 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs
@@ -24,7 +24,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
private readonly IZipClient _zipClient;
private readonly IFileSystem _fileSystem;
private readonly NativeEnvironment _environment;
- private readonly Assembly _ownerAssembly;
private readonly FFMpegInstallInfo _ffmpegInstallInfo;
private readonly string[] _fontUrls =
@@ -32,7 +31,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
"https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z"
};
- public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, NativeEnvironment environment, Assembly ownerAssembly, FFMpegInstallInfo ffmpegInstallInfo)
+ public FFMpegLoader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem, NativeEnvironment environment, FFMpegInstallInfo ffmpegInstallInfo)
{
_logger = logger;
_appPaths = appPaths;
@@ -40,7 +39,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
_zipClient = zipClient;
_fileSystem = fileSystem;
_environment = environment;
- _ownerAssembly = ownerAssembly;
_ffmpegInstallInfo = ffmpegInstallInfo;
}
@@ -55,13 +53,17 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
ProbePath = customffProbePath,
EncoderPath = customffMpegPath,
- Version = "custom"
+ Version = "external"
};
}
var downloadInfo = _ffmpegInstallInfo;
var version = downloadInfo.Version;
+ if (string.Equals(version, "0", StringComparison.OrdinalIgnoreCase))
+ {
+ return new FFMpegInfo();
+ }
if (string.Equals(version, "path", StringComparison.OrdinalIgnoreCase))
{
@@ -99,14 +101,8 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
}
else
{
- // Older version found.
- // Start with that. Download new version in the background.
- var newPath = versionedDirectoryPath;
- Task.Run(() => DownloadFFMpegInBackground(downloadInfo, newPath));
-
info = existingVersion;
versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath);
-
excludeFromDeletions.Add(versionedDirectoryPath);
}
}
@@ -183,36 +179,8 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
return null;
}
- private async void DownloadFFMpegInBackground(FFMpegInstallInfo downloadinfo, string directory)
- {
- try
- {
- await DownloadFFMpeg(downloadinfo, directory, new Progress<double>()).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error downloading ffmpeg", ex);
- }
- }
-
private async Task DownloadFFMpeg(FFMpegInstallInfo downloadinfo, string directory, IProgress<double> progress)
{
- if (downloadinfo.IsEmbedded)
- {
- var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString());
- _fileSystem.CreateDirectory(Path.GetDirectoryName(tempFile));
-
- using (var stream = _ownerAssembly.GetManifestResourceStream(downloadinfo.DownloadUrls[0]))
- {
- using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
- {
- await stream.CopyToAsync(fs).ConfigureAwait(false);
- }
- }
- ExtractFFMpeg(downloadinfo, tempFile, directory);
- return;
- }
-
foreach (var url in downloadinfo.DownloadUrls)
{
progress.Report(0);
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
index 0ae021407..d92dc1b96 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
@@ -21,13 +21,10 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
_fileSystem = fileSystem;
}
- public Tuple<List<string>,List<string>> Validate(FFMpegInfo info)
+ public Tuple<List<string>,List<string>> Validate(string encoderPath)
{
- _logger.Info("FFMpeg: {0}", info.EncoderPath);
- _logger.Info("FFProbe: {0}", info.ProbePath);
-
- var decoders = GetDecoders(info.EncoderPath);
- var encoders = GetEncoders(info.EncoderPath);
+ var decoders = GetDecoders(encoderPath);
+ var encoders = GetEncoders(encoderPath);
return new Tuple<List<string>, List<string>>(decoders, encoders);
}
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index a6d09d343..5b88a6bd9 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -71,6 +71,8 @@
<Compile Include="FFMpeg\FFmpegValidator.cs" />
<Compile Include="INativeApp.cs" />
<Compile Include="MbLinkShortcutHandler.cs" />
+ <Compile Include="Migrations\CollectionGroupingMigration.cs" />
+ <Compile Include="Migrations\CollectionsViewMigration.cs" />
<Compile Include="Migrations\FolderViewSettingMigration.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\DbMigration.cs" />
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs
new file mode 100644
index 000000000..b497eeb42
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/CollectionGroupingMigration.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class CollectionGroupingMigration : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IUserManager _userManager;
+
+ public CollectionGroupingMigration(IServerConfigurationManager config, IUserManager userManager)
+ {
+ _config = config;
+ _userManager = userManager;
+ }
+
+ public void Run()
+ {
+ var migrationKey = this.GetType().Name;
+ var migrationKeyList = _config.Configuration.Migrations.ToList();
+
+ if (!migrationKeyList.Contains(migrationKey))
+ {
+ if (_config.Configuration.IsStartupWizardCompleted)
+ {
+ if (_userManager.Users.Any(i => i.Configuration.GroupMoviesIntoBoxSets))
+ {
+ _config.Configuration.EnableGroupingIntoCollections = true;
+ }
+ }
+
+ migrationKeyList.Add(migrationKey);
+ _config.Configuration.Migrations = migrationKeyList.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs
new file mode 100644
index 000000000..c6186ce08
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/CollectionsViewMigration.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class CollectionsViewMigration : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly IUserManager _userManager;
+
+ public CollectionsViewMigration(IServerConfigurationManager config, IUserManager userManager)
+ {
+ _config = config;
+ _userManager = userManager;
+ }
+
+ public void Run()
+ {
+ var migrationKey = this.GetType().Name;
+ var migrationKeyList = _config.Configuration.Migrations.ToList();
+
+ if (!migrationKeyList.Contains(migrationKey))
+ {
+ if (_config.Configuration.IsStartupWizardCompleted)
+ {
+ if (_userManager.Users.Any(i => i.Configuration.DisplayCollectionsView))
+ {
+ _config.Configuration.DisplayCollectionsView = true;
+ }
+ }
+
+ migrationKeyList.Add(migrationKey);
+ _config.Configuration.Migrations = migrationKeyList.ToArray();
+ _config.SaveConfiguration();
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
index 65517c09c..f0cb9e84e 100644
--- a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
+++ b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
public void Run()
{
+ // If a forced migration is required, do that now
if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion)
{
if (!_config.Configuration.IsStartupWizardCompleted)
@@ -36,6 +37,25 @@ namespace MediaBrowser.Server.Startup.Common.Migrations
_taskManager.Execute<CleanDatabaseScheduledTask>();
});
+
+ return;
+ }
+
+ if (_config.Configuration.SchemaVersion < SqliteItemRepository.LatestSchemaVersion)
+ {
+ if (!_config.Configuration.IsStartupWizardCompleted)
+ {
+ _config.Configuration.SchemaVersion = SqliteItemRepository.LatestSchemaVersion;
+ _config.SaveConfiguration();
+ return;
+ }
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(1000).ConfigureAwait(false);
+
+ _taskManager.Execute<CleanDatabaseScheduledTask>();
+ });
}
}
}
diff --git a/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs b/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs
index 5b45afe73..b30509982 100644
--- a/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs
+++ b/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs
@@ -1,4 +1,5 @@
-
+using MediaBrowser.Model.System;
+
namespace MediaBrowser.Server.Startup.Common
{
public class NativeEnvironment
@@ -15,11 +16,4 @@ namespace MediaBrowser.Server.Startup.Common
Bsd = 2,
Linux = 3
}
-
- public enum Architecture
- {
- X86 = 0,
- X86_X64 = 1,
- Arm = 2
- }
}
diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config
index a92d92300..6d840c191 100644
--- a/MediaBrowser.ServerApplication/App.config
+++ b/MediaBrowser.ServerApplication/App.config
@@ -52,6 +52,7 @@
<bindingRedirect oldVersion="0.0.0.0-2.3.6.0" newVersion="2.3.6.0"/>
</dependentAssembly>
</assemblyBinding>
+ <enforceFIPSPolicy enabled="false"/>
</runtime>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 3a3b10188..fb4fb86ff 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -259,9 +259,6 @@ namespace MediaBrowser.ServerApplication
task = InstallVcredist2013IfNeeded(_appHost, _logger);
Task.WaitAll(task);
- task = InstallFrameworkV46IfNeeded(_logger);
- Task.WaitAll(task);
-
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
@@ -594,93 +591,6 @@ namespace MediaBrowser.ServerApplication
}
}
- private static async Task InstallFrameworkV46IfNeeded(ILogger logger)
- {
- bool installFrameworkV46 = false;
-
- try
- {
- using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
- .OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\"))
- {
- if (ndpKey != null && ndpKey.GetValue("Release") != null)
- {
- if ((int)ndpKey.GetValue("Release") <= 393295)
- {
- //Found framework V4, but not yet V4.6
- installFrameworkV46 = true;
- }
- }
- else
- {
- //Nothing found in the registry for V4
- installFrameworkV46 = true;
- }
- }
- }
- catch (Exception ex)
- {
- logger.ErrorException("Error getting .NET Framework version", ex);
- }
-
- _logger.Info(".NET Framework 4.6 found: {0}", !installFrameworkV46);
-
- if (installFrameworkV46)
- {
- try
- {
- await InstallFrameworkV46().ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- logger.ErrorException("Error installing .NET Framework version 4.6", ex);
- }
- }
- }
-
- private static async Task InstallFrameworkV46()
- {
- var httpClient = _appHost.HttpClient;
-
- var tmp = await httpClient.GetTempFile(new HttpRequestOptions
- {
- Url = "https://github.com/MediaBrowser/Emby.Resources/raw/master/netframeworkV46/NDP46-KB3045560-Web.exe",
- Progress = new Progress<double>()
-
- }).ConfigureAwait(false);
-
- var exePath = Path.ChangeExtension(tmp, ".exe");
- File.Copy(tmp, exePath);
-
- var startInfo = new ProcessStartInfo
- {
- FileName = exePath,
-
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- Verb = "runas",
- ErrorDialog = false,
- Arguments = "/q /norestart"
- };
-
-
- _logger.Info("Running {0}", startInfo.FileName);
-
- using (var process = Process.Start(startInfo))
- {
- process.WaitForExit();
- //process.ExitCode
- /*
- 0 --> Installation completed successfully.
- 1602 --> The user canceled installation.
- 1603 --> A fatal error occurred during installation.
- 1641 --> A restart is required to complete the installation. This message indicates success.
- 3010 --> A restart is required to complete the installation. This message indicates success.
- 5100 --> The user's computer does not meet system requirements.
- */
- }
- }
-
private static async Task InstallVcredist2013IfNeeded(ApplicationHost appHost, ILogger logger)
{
try
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 35660b2b1..fcd6f7faf 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -83,8 +83,8 @@
<Reference Include="System.Configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
- <Reference Include="System.Data.SQLite, Version=1.0.101.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
- <HintPath>..\packages\System.Data.SQLite.Core.1.0.101.0\lib\net46\System.Data.SQLite.dll</HintPath>
+ <Reference Include="System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+ <HintPath>..\packages\System.Data.SQLite.Core.1.0.102.0\lib\net46\System.Data.SQLite.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Drawing" />
@@ -1112,12 +1112,12 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
- <Import Project="..\packages\System.Data.SQLite.Core.1.0.101.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.101.0\build\net46\System.Data.SQLite.Core.targets')" />
+ <Import Project="..\packages\System.Data.SQLite.Core.1.0.102.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.102.0\build\net46\System.Data.SQLite.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.101.0\build\net46\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.101.0\build\net46\System.Data.SQLite.Core.targets'))" />
+ <Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.102.0\build\net46\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.102.0\build\net46\System.Data.SQLite.Core.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.ServerApplication/Native/DbConnector.cs b/MediaBrowser.ServerApplication/Native/DbConnector.cs
index 48ba7d0e7..9aaa96a80 100644
--- a/MediaBrowser.ServerApplication/Native/DbConnector.cs
+++ b/MediaBrowser.ServerApplication/Native/DbConnector.cs
@@ -16,18 +16,9 @@ namespace MediaBrowser.ServerApplication.Native
_logger = logger;
}
- public async Task<IDbConnection> Connect(string dbPath)
+ public Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null)
{
- try
- {
- return await SqliteExtensions.ConnectToDb(dbPath, _logger).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error opening database {0}", ex, dbPath);
-
- throw;
- }
+ return SqliteExtensions.ConnectToDb(dbPath, isReadOnly, enablePooling, cacheSize, _logger);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index f5abcf336..d8b2720c2 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -10,6 +10,7 @@ using System.Reflection;
using System.Windows.Forms;
using CommonIO;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Model.System;
using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem;
@@ -53,7 +54,7 @@ namespace MediaBrowser.ServerApplication.Native
return new NativeEnvironment
{
OperatingSystem = OperatingSystem.Windows,
- SystemArchitecture = System.Environment.Is64BitOperatingSystem ? Architecture.X86_X64 : Architecture.X86,
+ SystemArchitecture = System.Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86,
OperatingSystemVersionString = System.Environment.OSVersion.VersionString
};
}
@@ -158,10 +159,7 @@ namespace MediaBrowser.ServerApplication.Native
info.FFMpegFilename = "ffmpeg.exe";
info.FFProbeFilename = "ffprobe.exe";
- info.Version = "20160410";
- info.ArchiveType = "7z";
- info.IsEmbedded = false;
- info.DownloadUrls = GetDownloadUrls();
+ info.Version = "0";
return info;
}
@@ -206,25 +204,5 @@ namespace MediaBrowser.ServerApplication.Native
{
((Process)sender).Dispose();
}
-
- private string[] GetDownloadUrls()
- {
- switch (Environment.SystemArchitecture)
- {
- case Architecture.X86_X64:
- return new[]
- {
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win64.7z",
- "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20160409-git-0c90b2e-win64-static.7z"
- };
- case Architecture.X86:
- return new[]
- {
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win32.7z",
- "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20160409-git-0c90b2e-win32-static.7z"
- };
- }
- return new string[] { };
- }
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index cc9061fcd..ed60de9d2 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -89,19 +89,21 @@ namespace MediaBrowser.ServerApplication.Networking
/// </summary>
/// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
/// PC's in the Domain</returns>
- private IEnumerable<string> GetNetworkDevicesInternal()
+ private List<string> GetNetworkDevicesInternal()
{
//local fields
const int MAX_PREFERRED_LENGTH = -1;
var SV_TYPE_WORKSTATION = 1;
var SV_TYPE_SERVER = 2;
- var buffer = IntPtr.Zero;
- var tmpBuffer = IntPtr.Zero;
+ IntPtr buffer = IntPtr.Zero;
+ IntPtr tmpBuffer = IntPtr.Zero;
var entriesRead = 0;
var totalEntries = 0;
var resHandle = 0;
var sizeofINFO = Marshal.SizeOf(typeof(_SERVER_INFO_100));
+ var returnList = new List<string>();
+
try
{
//call the DllImport : NetServerEnum with all its required parameters
@@ -118,7 +120,7 @@ namespace MediaBrowser.ServerApplication.Networking
//get pointer to, Pointer to the buffer that received the data from
//the call to NetServerEnum. Must ensure to use correct size of
//STRUCTURE to ensure correct location in memory is pointed to
- tmpBuffer = new IntPtr((int)buffer + (i * sizeofINFO));
+ tmpBuffer = new IntPtr((Int64)buffer + (i * sizeofINFO));
//Have now got a pointer to the list of SV_TYPE_WORKSTATION and
//SV_TYPE_SERVER PC's, which is unmanaged memory
//Needs to Marshal data from an unmanaged block of memory to a
@@ -129,7 +131,7 @@ namespace MediaBrowser.ServerApplication.Networking
//add the PC names to the ArrayList
if (!string.IsNullOrEmpty(svrInfo.sv100_name))
{
- yield return svrInfo.sv100_name;
+ returnList.Add(svrInfo.sv100_name);
}
}
}
@@ -140,6 +142,8 @@ namespace MediaBrowser.ServerApplication.Networking
//the memory that the NetApiBufferAllocate function allocates
NativeMethods.NetApiBufferFree(buffer);
}
+
+ return returnList;
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 2d4baae25..a573c6fd9 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -3,5 +3,5 @@
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
<package id="ImageMagickSharp" version="1.0.0.18" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="System.Data.SQLite.Core" version="1.0.101.0" targetFramework="net46" />
+ <package id="System.Data.SQLite.Core" version="1.0.102.0" targetFramework="net46" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 904953cfc..08d5d73f2 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -133,7 +133,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetDashboardConfigurationPage request)
+ public Task<object> Get(GetDashboardConfigurationPage request)
{
var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
@@ -201,7 +201,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetDashboardResource request)
+ public async Task<object> Get(GetDashboardResource request)
{
var path = request.ResourceName;
@@ -230,7 +230,8 @@ namespace MediaBrowser.WebDashboard.Api
!contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) &&
!contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase))
{
- return ResultFactory.GetResult(GetResourceStream(path, localizationCulture).Result, contentType);
+ var stream = await GetResourceStream(path, localizationCulture).ConfigureAwait(false);
+ return ResultFactory.GetResult(stream, contentType);
}
TimeSpan? cacheDuration = null;
@@ -246,7 +247,7 @@ namespace MediaBrowser.WebDashboard.Api
var cacheKey = (assembly.Version + (localizationCulture ?? string.Empty) + path).GetMD5();
- return ResultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture));
+ return await ResultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture)).ConfigureAwait(false);
}
private string GetLocalizationCulture()
@@ -342,7 +343,9 @@ namespace MediaBrowser.WebDashboard.Api
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
- DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents"), "fonts");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "montserrat");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "opensans");
+ DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "roboto");
}
_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "jquery", "src"), true);
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 36693ad8e..4eae9975a 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -104,6 +104,9 @@
<Content Include="dashboard-ui\components\apphost.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\channelmapper\channelmapper.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\components\chromecasthelpers.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -131,6 +134,12 @@
<Content Include="dashboard-ui\components\metadataeditor\personeditor.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\navdrawer\navdrawer.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\navdrawer\navdrawer.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\components\remotecontrol.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -143,6 +152,9 @@
<Content Include="dashboard-ui\components\tvproviders\xmltv.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\userpasswordpage.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\components\viewcontainer-lite.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -152,9 +164,6 @@
<Content Include="dashboard-ui\css\images\logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\polymer\paper-icon-button-light.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\devices\windowsphone\wp.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -365,6 +374,12 @@
<Content Include="dashboard-ui\scripts\tvlatest.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\wizardcomponents.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\scripts\wizardcontroller.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\wizardlivetvguide.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -752,9 +767,6 @@
<Content Include="dashboard-ui\metadatasubtitles.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\collections.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\editor\missing.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -965,9 +977,6 @@
<Content Include="dashboard-ui\scripts\metadatasubtitles.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\musicalbumartists.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\livetvchannels.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1091,6 +1100,9 @@
<Content Include="dashboard-ui\wizardagreement.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\wizardcomponents.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\wizardlivetvguide.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1125,9 +1137,6 @@
<Content Include="dashboard-ui\music.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\alphapicker.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\imageeditor\imageeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index 18423f59e..63445b9c4 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -44,6 +44,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
}
else
{
+ // http://kodi.wiki/view/NFO_files/Movies
+ // movie.nfo will override all and any .nfo files in the same folder as the media files if you use the "Use foldernames for lookups" setting. If you don't, then moviename.nfo is used
+ //if (!item.IsInMixedFolder && item.ItemType == typeof(Movie))
+ //{
+ // list.Add(Path.Combine(item.ContainingFolderPath, "movie.nfo"));
+ //}
+
list.Add(Path.ChangeExtension(item.Path, ".nfo"));
}
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index a8ef26932..506bc4e36 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
- <version>3.0.650</version>
+ <version>3.0.651</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.650" />
+ <dependency id="MediaBrowser.Common" version="3.0.651" />
<dependency id="NLog" version="4.3.4" />
<dependency id="SimpleInjector" version="3.1.5" />
</dependencies>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 2bf899ad6..07bf6faa7 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.650</version>
+ <version>3.0.651</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 3fdeeaf53..c2616798e 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.650</version>
+ <version>3.0.651</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>