aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs8
-rw-r--r--MediaBrowser.Api/BaseApiService.cs189
-rw-r--r--MediaBrowser.Api/Library/LibraryHelpers.cs89
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs115
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs20
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs11
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs55
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs7
-rw-r--r--MediaBrowser.Api/Playback/StreamRequest.cs4
-rw-r--r--MediaBrowser.Api/Reports/ReportsService.cs6
-rw-r--r--MediaBrowser.Api/TvShowsService.cs5
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs8
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs5
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs8
-rw-r--r--MediaBrowser.Api/VideosService.cs16
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj10
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs4
-rw-r--r--MediaBrowser.Common.Implementations/packages.config6
-rw-r--r--MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs10
-rw-r--r--MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs3
-rw-r--r--MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs3
-rw-r--r--MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs3
-rw-r--r--MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs3
-rw-r--r--MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs40
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs41
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs69
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs19
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs93
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs27
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs296
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs7
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs19
-rw-r--r--MediaBrowser.Controller/Entities/GameSystem.cs13
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs19
-rw-r--r--MediaBrowser.Controller/Entities/IHasMetadata.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs11
-rw-r--r--MediaBrowser.Controller/Entities/IItemByName.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs17
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs28
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs18
-rw-r--r--MediaBrowser.Controller/Entities/PhotoAlbum.cs9
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs18
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs55
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs99
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs161
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs20
-rw-r--r--MediaBrowser.Controller/Entities/UserItemData.cs4
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs12
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs266
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs27
-rw-r--r--MediaBrowser.Controller/Health/IHealthMonitor.cs12
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs4
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs37
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs17
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs2
-rw-r--r--MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs11
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs20
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs28
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs26
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs3
-rw-r--r--MediaBrowser.Controller/Notifications/INotificationsRepository.cs6
-rw-r--r--MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs6
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs6
-rw-r--r--MediaBrowser.Controller/Persistence/IUserDataRepository.cs6
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs62
-rw-r--r--MediaBrowser.Controller/Providers/IProviderRepository.cs6
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs8
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs9
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs9
-rw-r--r--MediaBrowser.Dlna/Main/DlnaEntryPoint.cs8
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs11
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs8
-rw-r--r--MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs94
-rw-r--r--MediaBrowser.Dlna/Profiles/DefaultProfile.cs4
-rw-r--r--MediaBrowser.Dlna/Profiles/VlcProfile.cs93
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml31
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Default.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml8
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Kodi.xml6
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Vlc.xml29
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml10
-rw-r--r--MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml10
-rw-r--r--MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs30
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHandler.cs2
-rw-r--r--MediaBrowser.LocalMetadata/BaseXmlProvider.cs6
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs25
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs12
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs26
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs11
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj3
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Connect/ConnectUser.cs1
-rw-r--r--MediaBrowser.Model/Dlna/ILocalPlayer.cs13
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs45
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs5
-rw-r--r--MediaBrowser.Model/Dlna/TranscodingProfile.cs3
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs3
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs2
-rw-r--r--MediaBrowser.Model/Games/GameSystem.cs48
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs5
-rw-r--r--MediaBrowser.Model/LiveTv/ProgramQuery.cs3
-rw-r--r--MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs9
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj1
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItem.cs2
-rw-r--r--MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs6
-rw-r--r--MediaBrowser.Providers/Folders/DefaultImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs78
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs41
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs6
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs6
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs2
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs12
-rw-r--r--MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs4
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbImageProvider.cs8
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs12
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbSearch.cs4
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs4
-rw-r--r--MediaBrowser.Providers/Movies/MovieExternalIds.cs10
-rw-r--r--MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs12
-rw-r--r--MediaBrowser.Providers/Movies/TmdbSettings.cs2
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs8
-rw-r--r--MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs2
-rw-r--r--MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs4
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs18
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs35
-rw-r--r--MediaBrowser.Providers/Music/MusicExternalIds.cs12
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbItemProvider.cs13
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbProvider.cs2
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/DummySeasonProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs2
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs20
-rw-r--r--MediaBrowser.Providers/TV/SeasonMetadataService.cs41
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs129
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs12
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs19
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs11
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs42
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs14
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs8
-rw-r--r--MediaBrowser.Providers/TV/TvExternalIds.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs131
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs12
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs28
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs17
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs289
-rw-r--r--MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs24
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs16
-rw-r--r--MediaBrowser.Server.Implementations/Library/MusicManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs129
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs24
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs13
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs22
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs556
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs38
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs27
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs30
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs8
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs9
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-US.json353
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj16
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs (renamed from MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs)46
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs32
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs825
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs11
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs19
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs4
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs19
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs50
-rw-r--r--MediaBrowser.Server.Implementations/Social/SharingRepository.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs46
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncRepository.cs21
-rw-r--r--MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs84
-rw-r--r--MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs3
-rw-r--r--MediaBrowser.Server.Implementations/packages.config3
-rw-r--r--MediaBrowser.Server.Mac/Emby.Server.Mac.csproj199
-rw-r--r--MediaBrowser.Server.Mac/MenuBarIcon.cs6
-rw-r--r--MediaBrowser.Server.Mac/Native/BaseMonoApp.cs75
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj5
-rw-r--r--MediaBrowser.Server.Mono/Native/BaseMonoApp.cs21
-rw-r--r--MediaBrowser.Server.Mono/Native/NativeApp.cs7
-rw-r--r--MediaBrowser.Server.Mono/Native/SqliteExtensions.cs62
-rw-r--r--MediaBrowser.Server.Mono/Program.cs2
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs64
-rw-r--r--MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs59
-rw-r--r--MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs31
-rw-r--r--MediaBrowser.Server.Startup.Common/EntryPoints/StartupWizard.cs2
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs4
-rw-r--r--MediaBrowser.Server.Startup.Common/INativeApp.cs7
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs21
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj27
-rw-r--r--MediaBrowser.ServerApplication/Native/SqliteExtensions.cs62
-rw-r--r--MediaBrowser.ServerApplication/Native/Standby.cs40
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsApp.cs72
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs1
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkShares.cs4
-rw-r--r--MediaBrowser.ServerApplication/ServerNotifyIcon.cs15
-rw-r--r--MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id1
-rw-r--r--MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id1
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs11
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs2
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj67
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs6
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs4
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec8
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Model.Signed.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
-rw-r--r--OpenSubtitlesHandler/Utilities.cs4
274 files changed, 4874 insertions, 2829 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 66ca8c25d..a677bc600 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -488,13 +488,17 @@ namespace MediaBrowser.Api
{
try
{
- Logger.Info("Killing ffmpeg process for {0}", job.Path);
+ Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path);
//process.Kill();
process.StandardInput.WriteLine("q");
// Need to wait because killing is asynchronous
- process.WaitForExit(5000);
+ if (!process.WaitForExit(5000))
+ {
+ Logger.Info("Killing ffmpeg process for {0}", job.Path);
+ process.Kill();
+ }
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 30750b374..44d459a01 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -79,7 +79,7 @@ namespace MediaBrowser.Api
}
}
}
-
+
/// <summary>
/// To the optimized serialized result using cache.
/// </summary>
@@ -118,9 +118,6 @@ namespace MediaBrowser.Api
return ResultFactory.GetStaticFileResult(Request, path);
}
- private readonly char[] _dashReplaceChars = { '?', '/', '&' };
- private const char SlugChar = '-';
-
protected DtoOptions GetDtoOptions(object request)
{
var options = new DtoOptions();
@@ -154,152 +151,122 @@ namespace MediaBrowser.Api
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
{
- return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
- }
-
- protected Studio GetStudio(string name, ILibraryManager libraryManager)
- {
- return libraryManager.GetStudio(DeSlugStudioName(name, libraryManager));
- }
-
- protected Genre GetGenre(string name, ILibraryManager libraryManager)
- {
- return libraryManager.GetGenre(DeSlugGenreName(name, libraryManager));
- }
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
+ {
+ var result = libraryManager.GetItemList(new InternalItemsQuery
+ {
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(MusicArtist).Name }
- protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager)
- {
- return libraryManager.GetMusicGenre(DeSlugGenreName(name, libraryManager));
- }
+ }).OfType<MusicArtist>().FirstOrDefault();
- protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager)
- {
- return libraryManager.GetGameGenre(DeSlugGameGenreName(name, libraryManager));
- }
+ if (result != null)
+ {
+ return result;
+ }
+ }
- protected Person GetPerson(string name, ILibraryManager libraryManager)
- {
- return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager));
+ return libraryManager.GetArtist(name);
}
- /// <summary>
- /// Deslugs an artist name by finding the correct entry in the library
- /// </summary>
- /// <param name="name"></param>
- /// <param name="libraryManager"></param>
- /// <returns></returns>
- protected string DeSlugArtistName(string name, ILibraryManager libraryManager)
+ protected Studio GetStudio(string name, ILibraryManager libraryManager)
{
- if (name.IndexOf(SlugChar) == -1)
- {
- return name;
- }
-
- var items = libraryManager.GetItemList(new InternalItemsQuery
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
{
- IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name }
- });
-
- return items
- .OfType<IHasArtist>()
- .SelectMany(i => i.AllArtists)
- .DistinctNames()
- .FirstOrDefault(i =>
+ var result = libraryManager.GetItemList(new InternalItemsQuery
{
- i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(Studio).Name }
- return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
+ }).OfType<Studio>().FirstOrDefault();
+
+ if (result != null)
+ {
+ return result;
+ }
+ }
- }) ?? name;
+ return libraryManager.GetStudio(name);
}
- /// <summary>
- /// Deslugs a genre name by finding the correct entry in the library
- /// </summary>
- protected string DeSlugGenreName(string name, ILibraryManager libraryManager)
+ protected Genre GetGenre(string name, ILibraryManager libraryManager)
{
- if (name.IndexOf(SlugChar) == -1)
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
{
- return name;
- }
-
- return libraryManager.RootFolder.GetRecursiveChildren()
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .FirstOrDefault(i =>
+ var result = libraryManager.GetItemList(new InternalItemsQuery
{
- i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(Genre).Name }
- return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
+ }).OfType<Genre>().FirstOrDefault();
+
+ if (result != null)
+ {
+ return result;
+ }
+ }
- }) ?? name;
+ return libraryManager.GetGenre(name);
}
- protected string DeSlugGameGenreName(string name, ILibraryManager libraryManager)
+ protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager)
{
- if (name.IndexOf(SlugChar) == -1)
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
{
- return name;
- }
+ var result = libraryManager.GetItemList(new InternalItemsQuery
+ {
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(MusicGenre).Name }
- var items = libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Game).Name }
- });
+ }).OfType<MusicGenre>().FirstOrDefault();
- return items
- .SelectMany(i => i.Genres)
- .DistinctNames()
- .FirstOrDefault(i =>
+ if (result != null)
{
- i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
-
- return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
+ return result;
+ }
+ }
- }) ?? name;
+ return libraryManager.GetMusicGenre(name);
}
- /// <summary>
- /// Deslugs a studio name by finding the correct entry in the library
- /// </summary>
- protected string DeSlugStudioName(string name, ILibraryManager libraryManager)
+ protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager)
{
- if (name.IndexOf(SlugChar) == -1)
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
{
- return name;
- }
-
- return libraryManager.RootFolder
- .GetRecursiveChildren()
- .SelectMany(i => i.Studios)
- .DistinctNames()
- .FirstOrDefault(i =>
+ var result = libraryManager.GetItemList(new InternalItemsQuery
{
- i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(GameGenre).Name }
- return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
+ }).OfType<GameGenre>().FirstOrDefault();
- }) ?? name;
+ if (result != null)
+ {
+ return result;
+ }
+ }
+
+ return libraryManager.GetGameGenre(name);
}
- /// <summary>
- /// Deslugs a person name by finding the correct entry in the library
- /// </summary>
- protected string DeSlugPersonName(string name, ILibraryManager libraryManager)
+ protected Person GetPerson(string name, ILibraryManager libraryManager)
{
- if (name.IndexOf(SlugChar) == -1)
+ if (name.IndexOf(BaseItem.SlugChar) != -1)
{
- return name;
- }
-
- return libraryManager.GetPeopleNames(new InternalPeopleQuery())
- .FirstOrDefault(i =>
+ var result = libraryManager.GetItemList(new InternalItemsQuery
{
- i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
+ SlugName = name,
+ IncludeItemTypes = new[] { typeof(Person).Name }
- return string.Equals(i, name, StringComparison.OrdinalIgnoreCase);
+ }).OfType<Person>().FirstOrDefault();
+
+ if (result != null)
+ {
+ return result;
+ }
+ }
- }) ?? name;
+ return libraryManager.GetPerson(name);
}
protected string GetPathValue(int index)
diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs
deleted file mode 100644
index 46ec4f270..000000000
--- a/MediaBrowser.Api/Library/LibraryHelpers.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using MediaBrowser.Controller;
-using System;
-using System.IO;
-using System.Linq;
-using CommonIO;
-
-namespace MediaBrowser.Api.Library
-{
- /// <summary>
- /// Class LibraryHelpers
- /// </summary>
- public static class LibraryHelpers
- {
- /// <summary>
- /// The shortcut file extension
- /// </summary>
- private const string ShortcutFileExtension = ".mblink";
- /// <summary>
- /// The shortcut file search
- /// </summary>
- private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
-
- /// <summary>
- /// Deletes a shortcut from within a virtual folder, within either the default view or a user view
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="virtualFolderName">Name of the virtual folder.</param>
- /// <param name="mediaPath">The media path.</param>
- /// <param name="appPaths">The app paths.</param>
- /// <exception cref="System.IO.DirectoryNotFoundException">The media folder does not exist</exception>
- public static void RemoveMediaPath(IFileSystem fileSystem, string virtualFolderName, string mediaPath, IServerApplicationPaths appPaths)
- {
- if (string.IsNullOrWhiteSpace(mediaPath))
- {
- throw new ArgumentNullException("mediaPath");
- }
-
- var rootFolderPath = appPaths.DefaultUserViewsPath;
- var path = Path.Combine(rootFolderPath, virtualFolderName);
-
- if (!fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
- }
-
- var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
-
- if (!string.IsNullOrEmpty(shortcut))
- {
- fileSystem.DeleteFile(shortcut);
- }
- }
-
- /// <summary>
- /// Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="virtualFolderName">Name of the virtual folder.</param>
- /// <param name="path">The path.</param>
- /// <param name="appPaths">The app paths.</param>
- public static void AddMediaPath(IFileSystem fileSystem, string virtualFolderName, string path, IServerApplicationPaths appPaths)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (!fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The path does not exist.");
- }
-
- var rootFolderPath = appPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- var shortcutFilename = fileSystem.GetFileNameWithoutExtension(path);
-
- var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
-
- while (fileSystem.FileExists(lnk))
- {
- shortcutFilename += "1";
- lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
- }
-
- fileSystem.CreateShortcut(lnk, path);
- }
- }
-}
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index 244dcf09f..3cf0d5d93 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -190,75 +190,7 @@ namespace MediaBrowser.Api.Library
/// <param name="request">The request.</param>
public void Post(AddVirtualFolder request)
{
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException("request");
- }
-
- var name = _fileSystem.GetValidFilename(request.Name);
-
- var rootFolderPath = _appPaths.DefaultUserViewsPath;
-
- var virtualFolderPath = Path.Combine(rootFolderPath, name);
- while (_fileSystem.DirectoryExists(virtualFolderPath))
- {
- name += "1";
- virtualFolderPath = Path.Combine(rootFolderPath, name);
- }
-
- if (request.Paths != null)
- {
- var invalidpath = request.Paths.FirstOrDefault(i => !_fileSystem.DirectoryExists(i));
- if (invalidpath != null)
- {
- throw new ArgumentException("The specified path does not exist: " + invalidpath + ".");
- }
- }
-
- _libraryMonitor.Stop();
-
- try
- {
- _fileSystem.CreateDirectory(virtualFolderPath);
-
- if (!string.IsNullOrEmpty(request.CollectionType))
- {
- var path = Path.Combine(virtualFolderPath, request.CollectionType + ".collection");
-
- using (File.Create(path))
- {
-
- }
- }
-
- if (request.Paths != null)
- {
- foreach (var path in request.Paths)
- {
- LibraryHelpers.AddMediaPath(_fileSystem, name, path, _appPaths);
- }
- }
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (request.RefreshLibrary)
- {
- _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitor.Start();
- }
- });
- }
+ _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, request.RefreshLibrary);
}
/// <summary>
@@ -336,46 +268,7 @@ namespace MediaBrowser.Api.Library
/// <param name="request">The request.</param>
public void Delete(RemoveVirtualFolder request)
{
- if (string.IsNullOrWhiteSpace(request.Name))
- {
- throw new ArgumentNullException("request");
- }
-
- var rootFolderPath = _appPaths.DefaultUserViewsPath;
-
- var path = Path.Combine(rootFolderPath, request.Name);
-
- if (!_fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The media folder does not exist");
- }
-
- _libraryMonitor.Stop();
-
- try
- {
- _fileSystem.DeleteDirectory(path, true);
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (request.RefreshLibrary)
- {
- _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
-
- _libraryMonitor.Start();
- }
- });
- }
+ _libraryManager.RemoveVirtualFolder(request.Name, request.RefreshLibrary);
}
/// <summary>
@@ -393,7 +286,7 @@ namespace MediaBrowser.Api.Library
try
{
- LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, _appPaths);
+ _libraryManager.AddMediaPath(request.Name, request.Path);
}
finally
{
@@ -432,7 +325,7 @@ namespace MediaBrowser.Api.Library
try
{
- LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, _appPaths);
+ _libraryManager.RemoveMediaPath(request.Name, request.Path);
}
finally
{
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index ebcf8fbea..d3a4558c8 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -254,6 +254,8 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; }
+ public bool EnableTotalRecordCount { get; set; }
+
[ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? ImageTypeLimit { get; set; }
@@ -266,12 +268,24 @@ 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 GetPrograms()
+ {
+ EnableTotalRecordCount = true;
+ }
}
[Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
[Authenticated]
public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{
+ public bool EnableTotalRecordCount { get; set; }
+
+ public GetRecommendedPrograms()
+ {
+ EnableTotalRecordCount = true;
+ }
+
[ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
public string UserId { get; set; }
@@ -662,7 +676,8 @@ namespace MediaBrowser.Api.LiveTv
{
ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
UserId = request.UserId,
- HasAired = request.HasAired
+ HasAired = request.HasAired,
+ EnableTotalRecordCount = request.EnableTotalRecordCount
};
if (!string.IsNullOrEmpty(request.MinStartDate))
@@ -709,7 +724,8 @@ namespace MediaBrowser.Api.LiveTv
HasAired = request.HasAired,
IsMovie = request.IsMovie,
IsKids = request.IsKids,
- IsSports = request.IsSports
+ IsSports = request.IsSports,
+ EnableTotalRecordCount = request.EnableTotalRecordCount
};
var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index db8961a66..77949d179 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -129,7 +129,6 @@
<Compile Include="ItemUpdateService.cs" />
<Compile Include="Library\LibraryService.cs" />
<Compile Include="Library\FileOrganizationService.cs" />
- <Compile Include="Library\LibraryHelpers.cs" />
<Compile Include="Library\LibraryStructureService.cs" />
<Compile Include="LiveTv\LiveTvService.cs" />
<Compile Include="LocalizationService.cs" />
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 065f88268..786615cc3 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -144,7 +144,6 @@ namespace MediaBrowser.Api.Movies
var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
var movies = _libraryManager.GetItemList(query, parentIds);
- movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
var listEligibleForCategories = new List<BaseItem>();
var listEligibleForSuggestion = new List<BaseItem>();
@@ -197,12 +196,6 @@ namespace MediaBrowser.Api.Movies
var parentIds = new string[] { };
var list = _libraryManager.GetItemList(query, parentIds)
- .Where(i =>
- {
- // Strip out secondary versions
- var v = i as Video;
- return v != null && !v.PrimaryVersionId.HasValue;
- })
.DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
.ToList();
@@ -247,7 +240,7 @@ namespace MediaBrowser.Api.Movies
var recentlyPlayedMovies = allMoviesForCategories
.Select(i =>
{
- var userdata = _userDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userdata = _userDataRepository.GetUserData(user, i);
return new Tuple<BaseItem, bool, DateTime>(i, userdata.Played, userdata.LastPlayedDate ?? DateTime.MinValue);
})
.Where(i => i.Item2)
@@ -260,7 +253,7 @@ namespace MediaBrowser.Api.Movies
.Select(i =>
{
var score = 0;
- var userData = _userDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userData = _userDataRepository.GetUserData(user, i);
if (userData.IsFavorite)
{
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 901554973..792e46842 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -288,9 +288,9 @@ namespace MediaBrowser.Api.Playback
{
if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
-
- return "h264_qsv";
-
+
+ return "h264_qsv";
+
}
return "libx264";
@@ -712,15 +712,16 @@ namespace MediaBrowser.Api.Playback
inputChannels = null;
}
+ int? resultChannels = null;
var codec = outputAudioCodec ?? string.Empty;
if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
{
// wmav2 currently only supports two channel output
- return Math.Min(2, inputChannels ?? 2);
+ resultChannels = Math.Min(2, inputChannels ?? 2);
}
- if (request.MaxAudioChannels.HasValue)
+ else if (request.MaxAudioChannels.HasValue)
{
var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1
? 2
@@ -732,10 +733,18 @@ namespace MediaBrowser.Api.Playback
}
// If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels
- return Math.Min(request.MaxAudioChannels.Value, channelLimit);
+ resultChannels = Math.Min(request.MaxAudioChannels.Value, channelLimit);
+ }
+
+ if (resultChannels.HasValue && !string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ if (request.TranscodingMaxAudioChannels.HasValue)
+ {
+ resultChannels = Math.Min(request.TranscodingMaxAudioChannels.Value, resultChannels.Value);
+ }
}
- return request.AudioChannels;
+ return resultChannels ?? request.AudioChannels;
}
/// <summary>
@@ -821,9 +830,14 @@ namespace MediaBrowser.Api.Playback
/// <returns>System.String.</returns>
protected string GetVideoDecoder(StreamState state)
{
- if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
+
+ if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
{
- if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
switch (state.MediaSource.VideoStream.Codec.ToLower())
{
@@ -831,7 +845,8 @@ namespace MediaBrowser.Api.Playback
case "h264":
if (MediaEncoder.SupportsDecoder("h264_qsv"))
{
- return "-c:v h264_qsv ";
+ // Seeing stalls and failures with decoding. Not worth it compared to encoding.
+ //return "-c:v h264_qsv ";
}
break;
case "mpeg2video":
@@ -1033,7 +1048,7 @@ namespace MediaBrowser.Api.Playback
process.BeginOutputReadLine();
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
+ Task.Run(() => StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream));
// Wait for the file to exist before proceeeding
while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
@@ -1076,7 +1091,7 @@ namespace MediaBrowser.Api.Playback
return true;
}
- private async void StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
+ private async Task StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
{
try
{
@@ -1498,6 +1513,10 @@ namespace MediaBrowser.Api.Playback
}
}
}
+ else if (i == 26)
+ {
+ request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
+ }
}
}
@@ -1804,6 +1823,15 @@ namespace MediaBrowser.Api.Playback
}
}
+ if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase))
+ {
+ if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value)
+ {
+ Logger.Debug("Cannot stream copy video. Stream is marked as not AVC");
+ return false;
+ }
+ }
+
// Source and target codecs must match
if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase))
{
@@ -2222,9 +2250,10 @@ namespace MediaBrowser.Api.Playback
if (state.VideoRequest != null)
{
+ // Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase) && state.VideoRequest.CopyTimestamps)
{
- inputModifier += " -noaccurate_seek";
+ //inputModifier += " -noaccurate_seek";
}
}
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index ffe7c50c8..2d9cc40c0 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -15,6 +15,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Api.Playback
{
@@ -66,14 +67,16 @@ namespace MediaBrowser.Api.Playback
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
+ private readonly IMediaEncoder _mediaEncoder;
- public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager)
+ public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder)
{
_mediaSourceManager = mediaSourceManager;
_deviceManager = deviceManager;
_libraryManager = libraryManager;
_config = config;
_networkManager = networkManager;
+ _mediaEncoder = mediaEncoder;
}
public object Get(GetBitrateTestBytes request)
@@ -241,7 +244,7 @@ namespace MediaBrowser.Api.Playback
int? subtitleStreamIndex,
string playSessionId)
{
- var streamBuilder = new StreamBuilder(Logger);
+ var streamBuilder = new StreamBuilder(_mediaEncoder, Logger);
var options = new VideoOptions
{
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
index 371dbbda2..370915ec3 100644
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ b/MediaBrowser.Api/Playback/StreamRequest.cs
@@ -51,7 +51,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxAudioChannels { get; set; }
-
+
+ public int? TranscodingMaxAudioChannels { get; set; }
+
/// <summary>
/// Gets or sets the audio sample rate.
/// </summary>
diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs
index c3af09cd5..cb1615826 100644
--- a/MediaBrowser.Api/Reports/ReportsService.cs
+++ b/MediaBrowser.Api/Reports/ReportsService.cs
@@ -326,15 +326,15 @@ namespace MediaBrowser.Api.Reports
}
// Min official rating
- if (!string.IsNullOrEmpty(request.MinOfficialRating))
+ if (!string.IsNullOrWhiteSpace(request.MinOfficialRating))
{
query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
}
// Max official rating
- if (!string.IsNullOrEmpty(request.MaxOfficialRating))
+ if (!string.IsNullOrWhiteSpace(request.MaxOfficialRating))
{
- query.MaxParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
+ query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating);
}
// Artists
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index cd95d9f10..e3dfb7f5a 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -429,7 +429,7 @@ namespace MediaBrowser.Api
if (request.IsMissing.HasValue)
{
var val = request.IsMissing.Value;
- items = items.Where(i => i.IsMissingSeason == val);
+ items = items.Where(i => (i.IsMissingSeason ?? false) == val);
}
if (request.IsVirtualUnaired.HasValue)
@@ -508,8 +508,7 @@ namespace MediaBrowser.Api
returnItems = UserViewBuilder.FilterForAdjacency(returnItems, request.AdjacentTo);
}
- var returnList = _libraryManager.ReplaceVideosWithPrimaryVersions(returnItems)
- .ToList();
+ var returnList = returnItems.ToList();
var pagedItems = ApplyPaging(returnList, request.StartIndex, request.Limit);
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 6ae2b0832..b3164ce3f 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -274,7 +274,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
- var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(user, i);
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
});
@@ -284,7 +284,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
- var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(user, i);
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
});
@@ -294,7 +294,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
- var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(user, i);
var likes = userdata.Likes ?? false;
var favorite = userdata.IsFavorite;
@@ -307,7 +307,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
- var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(user, i);
return userdata != null && userdata.IsFavorite;
});
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index 6867f6308..aee1a8d54 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Api.UserLibrary
protected BaseItemsRequest()
{
EnableImages = true;
+ EnableTotalRecordCount = true;
}
/// <summary>
@@ -104,7 +105,9 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsInBoxSet { get; set; }
-
+
+ public bool EnableTotalRecordCount { get; set; }
+
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index cfdc40bb2..ff937078e 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -230,7 +230,8 @@ namespace MediaBrowser.Api.UserLibrary
ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId),
ParentIndexNumber = request.ParentIndexNumber,
AiredDuringSeason = request.AiredDuringSeason,
- AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater
+ AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater,
+ EnableTotalRecordCount = request.EnableTotalRecordCount
};
if (!string.IsNullOrWhiteSpace(request.Ids))
@@ -308,15 +309,15 @@ namespace MediaBrowser.Api.UserLibrary
}
// Min official rating
- if (!string.IsNullOrEmpty(request.MinOfficialRating))
+ if (!string.IsNullOrWhiteSpace(request.MinOfficialRating))
{
query.MinParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
}
// Max official rating
- if (!string.IsNullOrEmpty(request.MaxOfficialRating))
+ if (!string.IsNullOrWhiteSpace(request.MaxOfficialRating))
{
- query.MaxParentalRating = _localization.GetRatingLevel(request.MinOfficialRating);
+ query.MaxParentalRating = _localization.GetRatingLevel(request.MaxOfficialRating);
}
// Artists
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index c2c481cb6..8cc5cab35 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -519,10 +519,8 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : _libraryManager.GetItemById(itemId);
- var key = item.GetUserDataKey();
-
// Get the user data for this item
- var data = _userDataRepository.GetUserData(user.Id, key);
+ var data = _userDataRepository.GetUserData(user, item);
// Set favorite status
data.IsFavorite = isFavorite;
@@ -567,10 +565,8 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : _libraryManager.GetItemById(itemId);
- var key = item.GetUserDataKey();
-
// Get the user data for this item
- var data = _userDataRepository.GetUserData(user.Id, key);
+ var data = _userDataRepository.GetUserData(user, item);
data.Likes = likes;
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index c6ec69c85..c8dbb7bb2 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -130,6 +130,7 @@ namespace MediaBrowser.Api
var items = request.Ids.Split(',')
.Select(i => new Guid(i))
.Select(i => _libraryManager.GetItemById(i))
+ .OfType<Video>()
.ToList();
if (items.Count < 2)
@@ -137,14 +138,7 @@ namespace MediaBrowser.Api
throw new ArgumentException("Please supply at least two videos to merge.");
}
- if (items.Any(i => !(i is Video)))
- {
- throw new ArgumentException("Only videos can be grouped together.");
- }
-
- var videos = items.Cast<Video>().ToList();
-
- var videosWithVersions = videos.Where(i => i.MediaSourceCount > 1)
+ var videosWithVersions = items.Where(i => i.MediaSourceCount > 1)
.ToList();
if (videosWithVersions.Count > 1)
@@ -156,7 +150,7 @@ namespace MediaBrowser.Api
if (primaryVersion == null)
{
- primaryVersion = videos.OrderBy(i =>
+ primaryVersion = items.OrderBy(i =>
{
if (i.Video3DFormat.HasValue)
{
@@ -179,9 +173,9 @@ namespace MediaBrowser.Api
}).First();
}
- foreach (var item in videos.Where(i => i.Id != primaryVersion.Id))
+ foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
{
- item.PrimaryVersionId = primaryVersion.Id;
+ item.PrimaryVersionId = primaryVersion.Id.ToString("N");
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index 2017b40f4..8da1beb68 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -54,8 +54,9 @@
<Reference Include="MoreLinq">
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
</Reference>
- <Reference Include="NLog">
- <HintPath>..\packages\NLog.4.2.3\lib\net45\NLog.dll</HintPath>
+ <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+ <HintPath>..\packages\NLog.4.3.1\lib\net45\NLog.dll</HintPath>
+ <Private>True</Private>
</Reference>
<Reference Include="Patterns.Logging">
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
@@ -64,8 +65,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector">
- <HintPath>..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll</HintPath>
+ <Reference Include="SimpleInjector, Version=3.1.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <HintPath>..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll</HintPath>
+ <Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 8d727a112..090966d2b 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -311,7 +311,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
trigger.Triggered -= trigger_Triggered;
trigger.Triggered += trigger_Triggered;
- trigger.Start(LastExecutionResult, isApplicationStartup);
+ trigger.Start(LastExecutionResult, Logger, Name, isApplicationStartup);
}
}
@@ -339,7 +339,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
await Task.Delay(1000).ConfigureAwait(false);
- trigger.Start(LastExecutionResult, false);
+ trigger.Start(LastExecutionResult, Logger, Name, false);
}
private Task _currentTask;
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index 64b337221..6d7d86182 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -2,7 +2,7 @@
<packages>
<package id="CommonIO" version="1.0.0.9" targetFramework="net45" />
<package id="morelinq" version="1.4.0" targetFramework="net45" />
- <package id="NLog" version="4.2.3" targetFramework="net45" />
+ <package id="NLog" version="4.3.1" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="SimpleInjector" version="3.1.2" targetFramework="net45" />
-</packages>
+ <package id="SimpleInjector" version="3.1.3" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
index 382a41255..3d33e958d 100644
--- a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
@@ -1,7 +1,9 @@
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Tasks;
using System;
+using System.Globalization;
using System.Threading;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.ScheduledTasks
{
@@ -35,7 +37,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, bool isApplicationStartup)
+ public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
DisposeTimer();
@@ -44,7 +46,11 @@ namespace MediaBrowser.Common.ScheduledTasks
var triggerDate = now.TimeOfDay > TimeOfDay ? now.Date.AddDays(1) : now.Date;
triggerDate = triggerDate.Add(TimeOfDay);
- Timer = new Timer(state => OnTriggered(), null, triggerDate - now, TimeSpan.FromMilliseconds(-1));
+ var dueTime = triggerDate - now;
+
+ logger.Info("Daily trigger for {0} set to fire at {1}, which is {2} minutes from now.", taskName, triggerDate.ToString(), dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
+
+ Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
}
/// <summary>
diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
index 8c87f8f38..ef1ea9d38 100644
--- a/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Tasks;
using System;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.ScheduledTasks
{
@@ -19,7 +20,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- void Start(TaskResult lastResult, bool isApplicationStartup);
+ void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup);
/// <summary>
/// Stops waiting for the trigger action
diff --git a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
index e07dfcceb..5107db6c4 100644
--- a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.Tasks;
using System;
using System.Linq;
using System.Threading;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.ScheduledTasks
{
@@ -38,7 +39,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, bool isApplicationStartup)
+ public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
DisposeTimer();
diff --git a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
index 1d82dc76a..41f58a7ad 100644
--- a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Model.Tasks;
using System;
using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.ScheduledTasks
{
@@ -30,7 +31,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public async void Start(TaskResult lastResult, bool isApplicationStartup)
+ public async void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
if (isApplicationStartup)
{
diff --git a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
index eaf4afc75..9972dc804 100644
--- a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.Tasks;
using Microsoft.Win32;
using System;
using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.ScheduledTasks
{
@@ -30,7 +31,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, bool isApplicationStartup)
+ public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
switch (SystemEvent)
{
diff --git a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
index 2e38264b2..318802e07 100644
--- a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
namespace MediaBrowser.Common.ScheduledTasks
@@ -41,7 +42,7 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="isApplicationStartup">if set to <c>true</c> [is application startup].</param>
- public void Start(TaskResult lastResult, bool isApplicationStartup)
+ public void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup)
{
DisposeTimer();
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 929308ba0..c34a884ff 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.Controller.Entities.Audio
IArchivable
{
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
-
+
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
@@ -40,12 +40,6 @@ namespace MediaBrowser.Controller.Entities.Audio
public List<string> AlbumArtists { get; set; }
- /// <summary>
- /// Gets or sets the album.
- /// </summary>
- /// <value>The album.</value>
- public string Album { get; set; }
-
[IgnoreDataMember]
public bool IsThemeMedia
{
@@ -150,12 +144,10 @@ namespace MediaBrowser.Controller.Entities.Audio
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
+ var list = base.GetUserDataKeys();
+
if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
{
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty;
@@ -165,7 +157,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey;
}
- songKey+= Name;
+ songKey += Name;
if (!string.IsNullOrWhiteSpace(Album))
{
@@ -178,25 +170,25 @@ namespace MediaBrowser.Controller.Entities.Audio
songKey = albumArtist + "-" + songKey;
}
- return songKey;
+ list.Insert(0, songKey);
}
-
- var parent = AlbumEntity;
-
- if (parent != null)
+ else
{
- var parentKey = parent.GetUserDataKey();
+ var parent = AlbumEntity;
- if (IndexNumber.HasValue)
+ if (parent != null && IndexNumber.HasValue)
{
- var songKey = (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ") : "")
- + IndexNumber.Value.ToString("0000 - ");
+ list.InsertRange(0, parent.GetUserDataKeys().Select(i =>
+ {
+ var songKey = (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ") : "")
+ + IndexNumber.Value.ToString("0000 - ");
- return parentKey + songKey;
+ return i + songKey;
+ }));
}
}
- return base.CreateUserDataKey();
+ return list;
}
public override UnratedItem GetBlockUnratedType()
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index e6178c183..615276e83 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -49,6 +49,15 @@ namespace MediaBrowser.Controller.Entities.Audio
}
[IgnoreDataMember]
+ public override bool SupportsCumulativeRunTimeTicks
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ [IgnoreDataMember]
public List<string> AllArtists
{
get
@@ -96,36 +105,34 @@ namespace MediaBrowser.Controller.Entities.Audio
public List<string> Artists { get; set; }
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
+ var list = base.GetUserDataKeys();
- if (!string.IsNullOrWhiteSpace(id))
+ if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
{
- return "MusicAlbum-MusicBrainzReleaseGroup-" + id;
+ var albumArtist = AlbumArtist;
+ if (!string.IsNullOrWhiteSpace(albumArtist))
+ {
+ list.Insert(0, albumArtist + "-" + Name);
+ }
}
- id = this.GetProviderId(MetadataProviders.MusicBrainzAlbum);
+ var id = this.GetProviderId(MetadataProviders.MusicBrainzAlbum);
if (!string.IsNullOrWhiteSpace(id))
{
- return "MusicAlbum-Musicbrainz-" + id;
+ list.Insert(0, "MusicAlbum-Musicbrainz-" + id);
}
- if (ConfigurationManager.Configuration.EnableStandaloneMusicKeys)
+ id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
+
+ if (!string.IsNullOrWhiteSpace(id))
{
- var albumArtist = AlbumArtist;
- if (!string.IsNullOrWhiteSpace(albumArtist))
- {
- return albumArtist + "-" + Name;
- }
+ list.Insert(0, "MusicAlbum-MusicBrainzReleaseGroup-" + id);
}
- return base.CreateUserDataKey();
+ return list;
}
protected override bool GetBlockUnratedValue(UserPolicy config)
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 02bcceada..fb8a24061 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -17,7 +17,12 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasProductionLocations, IHasLookupInfo<ArtistInfo>
{
- public bool IsAccessedByName { get; set; }
+ [IgnoreDataMember]
+ public bool IsAccessedByName
+ {
+ get { return ParentId == Guid.Empty; }
+ }
+
public List<string> ProductionLocations { get; set; }
[IgnoreDataMember]
@@ -30,6 +35,15 @@ namespace MediaBrowser.Controller.Entities.Audio
}
[IgnoreDataMember]
+ public override bool SupportsCumulativeRunTimeTicks
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
@@ -40,6 +54,40 @@ namespace MediaBrowser.Controller.Entities.Audio
return !IsAccessedByName;
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ var itemByNameFilter = GetItemFilter();
+
+ if (query.User != null)
+ {
+ return query.User.RootFolder
+ .GetRecursiveChildren(query.User, i =>
+ {
+ if (query.IsFolder.HasValue)
+ {
+ if (query.IsFolder.Value != i.IsFolder)
+ {
+ return false;
+ }
+ }
+ return itemByNameFilter(i);
+ });
+ }
+
+ return LibraryManager.RootFolder
+ .GetRecursiveChildren(i =>
+ {
+ if (query.IsFolder.HasValue)
+ {
+ if (query.IsFolder.Value != i.IsFolder)
+ {
+ return false;
+ }
+ }
+ return itemByNameFilter(i);
+ });
+ }
+
protected override IEnumerable<BaseItem> ActualChildren
{
get
@@ -80,13 +128,12 @@ namespace MediaBrowser.Controller.Entities.Audio
ProductionLocations = new List<string>();
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return GetUserDataKey(this);
+ var list = base.GetUserDataKeys();
+
+ list.InsertRange(0, GetUserDataKeys(this));
+ return list;
}
/// <summary>
@@ -121,16 +168,18 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
- private static string GetUserDataKey(MusicArtist item)
+ private static List<string> GetUserDataKeys(MusicArtist item)
{
+ var list = new List<string>();
var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
if (!string.IsNullOrEmpty(id))
{
- return "Artist-Musicbrainz-" + id;
+ list.Add("Artist-Musicbrainz-" + id);
}
- return "Artist-" + item.Name;
+ list.Add("Artist-" + item.Name);
+ return list;
}
protected override bool GetBlockUnratedValue(UserPolicy config)
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index 45304d47e..77cf0cc49 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -10,13 +10,12 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicGenre : BaseItem, IItemByName
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "MusicGenre-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "MusicGenre-" + Name);
+ return list;
}
[IgnoreDataMember]
@@ -80,5 +79,13 @@ namespace MediaBrowser.Controller.Entities.Audio
return false;
}
}
+
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ query.Genres = new[] { Name };
+ query.IncludeItemTypes = new[] { typeof(MusicVideo).Name, typeof(Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
+
+ return LibraryManager.GetItemList(query);
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 959334d78..61060766f 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -44,6 +44,9 @@ namespace MediaBrowser.Controller.Entities
ImageInfos = new List<ItemImageInfo>();
}
+ public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
+ public static char SlugChar = '-';
+
/// <summary>
/// The supported image extensions
/// </summary>
@@ -67,6 +70,12 @@ namespace MediaBrowser.Controller.Entities
public List<ItemImageInfo> ImageInfos { get; set; }
/// <summary>
+ /// Gets or sets the album.
+ /// </summary>
+ /// <value>The album.</value>
+ public string Album { get; set; }
+
+ /// <summary>
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
@@ -125,6 +134,27 @@ namespace MediaBrowser.Controller.Entities
}
}
+ [IgnoreDataMember]
+ public string SlugName
+ {
+ get
+ {
+ var name = Name;
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ return string.Empty;
+ }
+
+ return SlugReplaceChars.Aggregate(name, (current, c) => current.Replace(c, SlugChar));
+ }
+ }
+
+ [IgnoreDataMember]
+ public bool IsUnaired
+ {
+ get { return PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date; }
+ }
+
public string OriginalTitle { get; set; }
/// <summary>
@@ -605,7 +635,7 @@ namespace MediaBrowser.Controller.Entities
builder.Append(chunkBuilder);
}
//Logger.Debug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
- return builder.ToString();
+ return builder.ToString().RemoveDiacritics();
}
[IgnoreDataMember]
@@ -728,12 +758,14 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the critic rating.
/// </summary>
/// <value>The critic rating.</value>
+ [IgnoreDataMember]
public float? CriticRating { get; set; }
/// <summary>
/// Gets or sets the critic rating summary.
/// </summary>
/// <value>The critic rating summary.</value>
+ [IgnoreDataMember]
public string CriticRatingSummary { get; set; }
/// <summary>
@@ -1149,33 +1181,31 @@ namespace MediaBrowser.Controller.Entities
get { return null; }
}
- private string _userDataKey;
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- public string GetUserDataKey()
+ [IgnoreDataMember]
+ public virtual string PresentationUniqueKey
{
- if (string.IsNullOrWhiteSpace(_userDataKey))
- {
- var key = CreateUserDataKey();
- _userDataKey = key;
- return key;
- }
+ get { return Id.ToString("N"); }
+ }
- return _userDataKey;
+ public virtual bool RequiresRefresh()
+ {
+ return false;
}
- protected virtual string CreateUserDataKey()
+ public virtual List<string> GetUserDataKeys()
{
+ var list = new List<string>();
+
if (SourceType == SourceType.Channel)
{
if (!string.IsNullOrWhiteSpace(ExternalId))
{
- return ExternalId;
+ list.Add(ExternalId);
}
}
- return Id.ToString();
+
+ list.Add(Id.ToString());
+ return list;
}
internal virtual bool IsValidFromResolver(BaseItem newItem)
@@ -1188,7 +1218,6 @@ namespace MediaBrowser.Controller.Entities
public void AfterMetadataRefresh()
{
_sortName = null;
- _userDataKey = null;
}
/// <summary>
@@ -1542,11 +1571,11 @@ namespace MediaBrowser.Controller.Entities
{
if (!string.IsNullOrEmpty(info.Path))
{
- var itemByPath = LibraryManager.FindByPath(info.Path);
+ var itemByPath = LibraryManager.FindByPath(info.Path, null);
if (itemByPath == null)
{
- Logger.Warn("Unable to find linked item at path {0}", info.Path);
+ //Logger.Warn("Unable to find linked item at path {0}", info.Path);
}
return itemByPath;
@@ -1555,6 +1584,15 @@ namespace MediaBrowser.Controller.Entities
return null;
}
+ [IgnoreDataMember]
+ public virtual bool EnableRememberingTrackSelections
+ {
+ get
+ {
+ return true;
+ }
+ }
+
/// <summary>
/// Adds a studio to the item
/// </summary>
@@ -1608,9 +1646,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException();
}
- var key = GetUserDataKey();
-
- var data = UserDataManager.GetUserData(user.Id, key);
+ var data = UserDataManager.GetUserData(user, this);
if (datePlayed.HasValue)
{
@@ -1645,9 +1681,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException();
}
- var key = GetUserDataKey();
-
- var data = UserDataManager.GetUserData(user.Id, key);
+ var data = UserDataManager.GetUserData(user, this);
//I think it is okay to do this here.
// if this is only called when a user is manually forcing something to un-played
@@ -1978,14 +2012,14 @@ namespace MediaBrowser.Controller.Entities
public virtual bool IsPlayed(User user)
{
- var userdata = UserDataManager.GetUserData(user.Id, GetUserDataKey());
+ var userdata = UserDataManager.GetUserData(user, this);
return userdata != null && userdata.Played;
}
public bool IsFavoriteOrLiked(User user)
{
- var userdata = UserDataManager.GetUserData(user.Id, GetUserDataKey());
+ var userdata = UserDataManager.GetUserData(user, this);
return userdata != null && (userdata.IsFavorite || (userdata.Likes ?? false));
}
@@ -1997,7 +2031,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("user");
}
- var userdata = UserDataManager.GetUserData(user.Id, GetUserDataKey());
+ var userdata = UserDataManager.GetUserData(user, this);
return userdata == null || !userdata.Played;
}
@@ -2028,7 +2062,6 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public virtual bool BeforeMetadataRefresh()
{
- _userDataKey = null;
_sortName = null;
var hasChanges = false;
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 429700327..5e0cf6e88 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -8,6 +8,7 @@ using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MoreLinq;
namespace MediaBrowser.Controller.Entities
{
@@ -97,7 +98,6 @@ namespace MediaBrowser.Controller.Entities
}
}
-
return base.IsValidFromResolver(newItem);
}
@@ -200,9 +200,30 @@ namespace MediaBrowser.Controller.Entities
public IEnumerable<Folder> GetPhysicalParents()
{
- return LibraryManager.RootFolder.Children
+ var rootChildren = LibraryManager.RootFolder.Children
.OfType<Folder>()
- .Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase));
+ .ToList();
+
+ return PhysicalLocations.Where(i => !string.Equals(i, Path, StringComparison.OrdinalIgnoreCase)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id);
+ }
+
+ private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
+ {
+ var result = rootChildren
+ .Where(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ if (result.Count == 0)
+ {
+ var folder = LibraryManager.FindByPath(path, true) as Folder;
+
+ if (folder != null)
+ {
+ result.Add(folder);
+ }
+ }
+
+ return result;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index f4cdc8fa1..77e362419 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -28,6 +28,9 @@ namespace MediaBrowser.Controller.Entities
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
+ [IgnoreDataMember]
+ public DateTime? DateLastMediaAdded { get; set; }
+
public Folder()
{
LinkedChildren = new List<LinkedChild>();
@@ -56,6 +59,36 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
+ public virtual bool SupportsCumulativeRunTimeTicks
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ [IgnoreDataMember]
+ public virtual bool SupportsDateLastMediaAdded
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override bool RequiresRefresh()
+ {
+ var baseResult = base.RequiresRefresh();
+
+ if (SupportsCumulativeRunTimeTicks && !RunTimeTicks.HasValue)
+ {
+ baseResult = true;
+ }
+
+ return baseResult;
+ }
+
+ [IgnoreDataMember]
public override string FileNameWithoutExtension
{
get
@@ -199,8 +232,8 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Dictionary{System.StringFunc{UserIEnumerable{BaseItem}}}.</returns>
protected virtual IEnumerable<string> GetIndexByOptions()
{
- return new List<string> {
- {"None"},
+ return new List<string> {
+ {"None"},
{"Performer"},
{"Genre"},
{"Director"},
@@ -707,8 +740,8 @@ namespace MediaBrowser.Controller.Entities
{
return ItemRepository.GetItemIdsList(new InternalItemsQuery
{
- ParentId = Id
-
+ ParentId = Id,
+ GroupByPresentationUniqueKey = false
});
}
@@ -751,39 +784,44 @@ namespace MediaBrowser.Controller.Entities
return true;
}
}
+
+ var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76;
if (query.SortBy != null && query.SortBy.Length > 0)
{
- if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.DatePlayed");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
+ if (!supportsUserDataQueries)
{
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
- return true;
- }
- if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
- return true;
+ if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
+ {
+ Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
+ {
+ Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
+ {
+ Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
+ {
+ Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
+ {
+ Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
+ return true;
+ }
}
if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.Album, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.Album");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
@@ -799,11 +837,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.DateLastContentAdded, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.DateLastContentAdded");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem");
@@ -819,11 +852,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
@@ -839,11 +867,6 @@ namespace MediaBrowser.Controller.Entities
Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName");
return true;
}
- if (query.SortBy.Contains(ItemSortBy.StartDate, StringComparer.OrdinalIgnoreCase))
- {
- Logger.Debug("Query requires post-filtering due to ItemSortBy.StartDate");
- return true;
- }
if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase))
{
Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio");
@@ -868,34 +891,37 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.IsLiked.HasValue)
+ if (!supportsUserDataQueries)
{
- Logger.Debug("Query requires post-filtering due to IsLiked");
- return true;
- }
+ if (query.IsLiked.HasValue)
+ {
+ Logger.Debug("Query requires post-filtering due to IsLiked");
+ return true;
+ }
- if (query.IsFavoriteOrLiked.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
- return true;
- }
+ if (query.IsFavoriteOrLiked.HasValue)
+ {
+ Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
+ return true;
+ }
- if (query.IsFavorite.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsFavorite");
- return true;
- }
+ if (query.IsFavorite.HasValue)
+ {
+ Logger.Debug("Query requires post-filtering due to IsFavorite");
+ return true;
+ }
- if (query.IsResumable.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsResumable");
- return true;
- }
+ if (query.IsResumable.HasValue)
+ {
+ Logger.Debug("Query requires post-filtering due to IsResumable");
+ return true;
+ }
- if (query.IsPlayed.HasValue)
- {
- Logger.Debug("Query requires post-filtering due to IsPlayed");
- return true;
+ if (query.IsPlayed.HasValue)
+ {
+ Logger.Debug("Query requires post-filtering due to IsPlayed");
+ return true;
+ }
}
if (query.IsInBoxSet.HasValue)
@@ -1059,30 +1085,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (!string.IsNullOrWhiteSpace(query.NameContains))
- {
- Logger.Debug("Query requires post-filtering due to NameContains");
- return true;
- }
-
- if (!string.IsNullOrWhiteSpace(query.NameLessThan))
- {
- Logger.Debug("Query requires post-filtering due to NameLessThan");
- return true;
- }
-
- if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
- {
- Logger.Debug("Query requires post-filtering due to NameStartsWith");
- return true;
- }
-
- if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater))
- {
- Logger.Debug("Query requires post-filtering due to NameStartsWithOrGreater");
- return true;
- }
-
if (query.AirDays.Length > 0)
{
Logger.Debug("Query requires post-filtering due to AirDays");
@@ -1107,12 +1109,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.AlbumNames.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to AlbumNames");
- return true;
- }
-
if (query.ArtistNames.Length > 0)
{
Logger.Debug("Query requires post-filtering due to ArtistNames");
@@ -1297,33 +1293,42 @@ namespace MediaBrowser.Controller.Entities
public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter)
{
- var list = new List<BaseItem>();
+ var result = new Dictionary<Guid, BaseItem>();
- AddChildrenToList(list, true, filter);
+ AddChildrenToList(result, true, true, filter);
- return list;
+ return result.Values.ToList();
}
/// <summary>
/// Adds the children to list.
/// </summary>
- /// <param name="list">The list.</param>
- /// <param name="recursive">if set to <c>true</c> [recursive].</param>
- /// <param name="filter">The filter.</param>
- private void AddChildrenToList(List<BaseItem> list, bool recursive, Func<BaseItem, bool> filter)
+ private void AddChildrenToList(Dictionary<Guid,BaseItem> result, bool includeLinkedChildren, bool recursive, Func<BaseItem, bool> filter)
{
foreach (var child in Children)
{
if (filter == null || filter(child))
{
- list.Add(child);
+ result[child.Id] = child;
}
if (recursive && child.IsFolder)
{
var folder = (Folder)child;
- folder.AddChildrenToList(list, true, filter);
+ // We can only support includeLinkedChildren for the first folder, or we might end up stuck in a loop of linked items
+ folder.AddChildrenToList(result, false, true, filter);
+ }
+ }
+
+ if (includeLinkedChildren)
+ {
+ foreach (var child in GetLinkedChildren())
+ {
+ if (filter == null || filter(child))
+ {
+ result[child.Id] = child;
+ }
}
}
}
@@ -1567,38 +1572,17 @@ namespace MediaBrowser.Controller.Entities
await Task.WhenAll(tasks).ConfigureAwait(false);
}
- /// <summary>
- /// Finds an item by path, recursively
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>BaseItem.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- public BaseItem FindByPath(string path)
+ public override bool IsPlayed(User user)
{
- if (string.IsNullOrEmpty(path))
+ var itemsResult = GetItems(new InternalItemsQuery(user)
{
- throw new ArgumentNullException();
- }
-
- if (string.Equals(Path, path, StringComparison.OrdinalIgnoreCase))
- {
- return this;
- }
-
- if (PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase))
- {
- return this;
- }
+ Recursive = true,
+ IsFolder = false,
+ ExcludeLocationTypes = new[] { LocationType.Virtual }
- return GetRecursiveChildren(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) ||
- (!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) ||
- i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase))
- .FirstOrDefault();
- }
+ }).Result;
- public override bool IsPlayed(User user)
- {
- return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
+ return itemsResult.Items
.All(i => i.IsPlayed(user));
}
@@ -1607,26 +1591,50 @@ namespace MediaBrowser.Controller.Entities
return !IsPlayed(user);
}
+ [IgnoreDataMember]
+ public virtual bool SupportsUserDataFromChildren
+ {
+ get
+ {
+ // These are just far too slow.
+ if (this is ICollectionFolder)
+ {
+ return false;
+ }
+ if (this is UserView)
+ {
+ return false;
+ }
+ if (this is UserRootFolder)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
{
+ if (!SupportsUserDataFromChildren)
+ {
+ return;
+ }
+
var recursiveItemCount = 0;
var unplayed = 0;
double totalPercentPlayed = 0;
- IEnumerable<BaseItem> children;
- var folder = this;
+ var itemsResult = GetItems(new InternalItemsQuery(user)
+ {
+ Recursive = true,
+ IsFolder = false,
+ ExcludeLocationTypes = new[] { LocationType.Virtual }
- var season = folder as Season;
+ }).Result;
- if (season != null)
- {
- children = season.GetEpisodes(user).Where(i => i.LocationType != LocationType.Virtual);
- }
- else
- {
- children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual);
- }
+ var children = itemsResult.Items;
// Loop through each recursive child
foreach (var child in children)
@@ -1635,7 +1643,7 @@ namespace MediaBrowser.Controller.Entities
var isUnplayed = true;
- var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey());
+ var itemUserData = UserDataManager.GetUserData(user, child);
// Incrememt totalPercentPlayed
if (itemUserData != null)
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index e597b2a15..9ed240046 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -76,15 +76,16 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public List<string> MultiPartGameFiles { get; set; }
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
+ var list = base.GetUserDataKeys();
var id = this.GetProviderId(MetadataProviders.Gamesdb);
if (!string.IsNullOrEmpty(id))
{
- return "Game-Gamesdb-" + id;
+ list.Insert(0, "Game-Gamesdb-" + id);
}
- return base.CreateUserDataKey();
+ return list;
}
public override IEnumerable<string> GetDeletePaths()
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
index d2b6b4856..7c1e88cb1 100644
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ b/MediaBrowser.Controller/Entities/GameGenre.cs
@@ -7,13 +7,12 @@ namespace MediaBrowser.Controller.Entities
{
public class GameGenre : BaseItem, IItemByName
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "GameGenre-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "GameGenre-" + Name);
+ return list;
}
/// <summary>
@@ -63,6 +62,14 @@ namespace MediaBrowser.Controller.Entities
return i => i is Game && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ query.Genres = new[] { Name };
+ query.IncludeItemTypes = new[] { typeof(Game).Name };
+
+ return LibraryManager.GetItemList(query);
+ }
+
[IgnoreDataMember]
public override bool SupportsPeople
{
diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs
index bc35c4738..1c09ee507 100644
--- a/MediaBrowser.Controller/Entities/GameSystem.cs
+++ b/MediaBrowser.Controller/Entities/GameSystem.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using System;
+using System.Collections.Generic;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
@@ -31,17 +32,15 @@ namespace MediaBrowser.Controller.Entities
/// <value>The game system.</value>
public string GameSystemName { get; set; }
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
+ var list = base.GetUserDataKeys();
+
if (!string.IsNullOrEmpty(GameSystemName))
{
- return "GameSystem-" + GameSystemName;
+ list.Insert(0, "GameSystem-" + GameSystemName);
}
- return base.CreateUserDataKey();
+ return list;
}
protected override bool GetBlockUnratedValue(UserPolicy config)
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 233e1e0fd..c87d4daaf 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -11,13 +11,12 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Genre : BaseItem, IItemByName
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "Genre-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "Genre-" + Name);
+ return list;
}
/// <summary>
@@ -67,6 +66,14 @@ namespace MediaBrowser.Controller.Entities
return i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ query.Genres = new[] { Name };
+ query.ExcludeItemTypes = new[] { typeof(Game).Name, typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
+
+ return LibraryManager.GetItemList(query);
+ }
+
[IgnoreDataMember]
public override bool SupportsPeople
{
diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs
index 1f680b35f..c7940c8a9 100644
--- a/MediaBrowser.Controller/Entities/IHasMetadata.cs
+++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs
@@ -49,5 +49,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value><c>true</c> if [supports people]; otherwise, <c>false</c>.</value>
bool SupportsPeople { get; }
+
+ bool RequiresRefresh();
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index 34a820853..244b319bd 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Dto;
+using System.Collections.Generic;
+using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Entities
{
@@ -7,11 +8,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public interface IHasUserData : IHasId
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- string GetUserDataKey();
+ List<string> GetUserDataKeys();
/// <summary>
/// Fills the user data dto values.
@@ -20,5 +17,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="userData">The user data.</param>
/// <param name="user">The user.</param>
void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user);
+
+ bool EnableRememberingTrackSelections { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs
index e6667290c..7747e738c 100644
--- a/MediaBrowser.Controller/Entities/IItemByName.cs
+++ b/MediaBrowser.Controller/Entities/IItemByName.cs
@@ -20,6 +20,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <returns>Func&lt;BaseItem, System.Boolean&gt;.</returns>
Func<BaseItem, bool> GetItemFilter();
+
+ IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query);
}
public interface IHasDualAccess : IItemByName
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index fbf246b3a..5236b0a27 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -46,8 +46,11 @@ namespace MediaBrowser.Controller.Entities
public string NameLessThan { get; set; }
public string NameContains { get; set; }
+ public string PresentationUniqueKey { get; set; }
public string Path { get; set; }
-
+ public string Name { get; set; }
+ public string SlugName { get; set; }
+
public string Person { get; set; }
public string[] PersonIds { get; set; }
public string[] ItemIds { get; set; }
@@ -106,6 +109,7 @@ namespace MediaBrowser.Controller.Entities
internal List<Guid> ItemIdsFromPersonFilters { get; set; }
public int? ParentIndexNumber { get; set; }
+ public int? IndexNumber { get; set; }
public int? MinParentalRating { get; set; }
public int? MaxParentalRating { get; set; }
@@ -123,7 +127,6 @@ namespace MediaBrowser.Controller.Entities
public SourceType[] SourceTypes { get; set; }
public SourceType[] ExcludeSourceTypes { get; set; }
public TrailerType[] TrailerTypes { get; set; }
- public TrailerType[] ExcludeTrailerTypes { get; set; }
public DayOfWeek[] AirDays { get; set; }
public SeriesStatus[] SeriesStatuses { get; set; }
@@ -131,9 +134,16 @@ namespace MediaBrowser.Controller.Entities
public string[] AlbumNames { get; set; }
public string[] ArtistNames { get; set; }
-
+ public string AncestorWithPresentationUniqueKey { get; set; }
+
+ public bool GroupByPresentationUniqueKey { get; set; }
+ public bool EnableTotalRecordCount { get; set; }
+
public InternalItemsQuery()
{
+ GroupByPresentationUniqueKey = true;
+ EnableTotalRecordCount = true;
+
AlbumNames = new string[] { };
ArtistNames = new string[] { };
@@ -165,7 +175,6 @@ namespace MediaBrowser.Controller.Entities
SourceTypes = new SourceType[] { };
ExcludeSourceTypes = new SourceType[] { };
TrailerTypes = new TrailerType[] { };
- ExcludeTrailerTypes = new TrailerType[] { };
AirDays = new DayOfWeek[] { };
SeriesStatuses = new SeriesStatus[] { };
}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index cd3e07ea3..09a9d97bc 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -118,7 +119,7 @@ namespace MediaBrowser.Controller.Entities.Movies
// Gather all possible ratings
var ratings = GetRecursiveChildren()
.Concat(GetLinkedChildren())
- .Where(i => i is Movie || i is Series)
+ .Where(i => i is Movie || i is Series || i is MusicAlbum || i is Game)
.Select(i => i.OfficialRating)
.Where(i => !string.IsNullOrEmpty(i))
.Distinct(StringComparer.OrdinalIgnoreCase)
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 6004992cc..5882b5f4d 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -75,34 +75,6 @@ namespace MediaBrowser.Controller.Entities.Movies
get { return TmdbCollectionName; }
set { TmdbCollectionName = value; }
}
-
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
- {
- var key = GetMovieUserDataKey(this);
-
- if (string.IsNullOrWhiteSpace(key))
- {
- key = base.CreateUserDataKey();
- }
-
- return key;
- }
-
- public static string GetMovieUserDataKey(BaseItem movie)
- {
- var key = movie.GetProviderId(MetadataProviders.Tmdb);
-
- if (string.IsNullOrWhiteSpace(key))
- {
- key = movie.GetProviderId(MetadataProviders.Imdb);
- }
-
- return key;
- }
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index b52f16a46..7119828e2 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -10,12 +10,6 @@ namespace MediaBrowser.Controller.Entities
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo<MusicVideoInfo>
{
/// <summary>
- /// Gets or sets the album.
- /// </summary>
- /// <value>The album.</value>
- public string Album { get; set; }
-
- /// <summary>
/// Gets or sets the budget.
/// </summary>
/// <value>The budget.</value>
@@ -44,15 +38,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
- {
- return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey();
- }
-
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index 560ea6e05..2b099e3d5 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -18,13 +18,12 @@ namespace MediaBrowser.Controller.Entities
/// <value>The place of birth.</value>
public string PlaceOfBirth { get; set; }
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "Person-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "Person-" + Name);
+ return list;
}
public PersonLookupInfo GetLookupInfo()
@@ -32,6 +31,13 @@ namespace MediaBrowser.Controller.Entities
return GetItemLookupInfo<PersonLookupInfo>();
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ query.Person = Name;
+
+ return LibraryManager.GetItemList(query);
+ }
+
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
index c8ab67a69..b0ddcfb8c 100644
--- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs
+++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
@@ -8,15 +8,6 @@ namespace MediaBrowser.Controller.Entities
public class PhotoAlbum : Folder
{
[IgnoreDataMember]
- public override bool SupportsLocalMetadata
- {
- get
- {
- return false;
- }
- }
-
- [IgnoreDataMember]
public override bool AlwaysScanInternalMetadataPath
{
get
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index a55527f37..48ca7bbcc 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -10,13 +10,12 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Studio : BaseItem, IItemByName, IHasTags
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "Studio-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "Studio-" + Name);
+ return list;
}
/// <summary>
@@ -66,6 +65,13 @@ namespace MediaBrowser.Controller.Entities
return i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase);
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ query.Studios = new[] { Name };
+
+ return LibraryManager.GetItemList(query);
+ }
+
[IgnoreDataMember]
public override bool SupportsPeople
{
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index e1a91086b..a4b0b3082 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -58,60 +58,48 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? PhysicalSeasonNumber;
+ return AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? ParentIndexNumber;
}
}
[IgnoreDataMember]
- public int? PhysicalSeasonNumber
+ public override Folder LatestItemsIndexContainer
{
get
{
- var value = ParentIndexNumber;
-
- if (value.HasValue)
- {
- return value;
- }
-
- var season = Season;
-
- return season != null ? season.IndexNumber : null;
+ return Series;
}
}
[IgnoreDataMember]
- public override Folder LatestItemsIndexContainer
+ public override Guid? DisplayParentId
{
get
{
- return Series;
+ return SeasonId;
}
}
[IgnoreDataMember]
- public override Guid? DisplayParentId
+ protected override bool EnableDefaultVideoUserDataKeys
{
get
{
- return SeasonId;
+ return false;
}
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- var series = Series;
+ var list = base.GetUserDataKeys();
+ var series = Series;
if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
{
- return series.GetUserDataKey() + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000");
+ list.InsertRange(0, series.GetUserDataKeys().Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
}
- return base.CreateUserDataKey();
+ return list;
}
/// <summary>
@@ -223,12 +211,6 @@ namespace MediaBrowser.Controller.Entities.TV
}
[IgnoreDataMember]
- public bool IsUnaired
- {
- get { return PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date; }
- }
-
- [IgnoreDataMember]
public bool IsVirtualUnaired
{
get { return LocationType == LocationType.Virtual && IsUnaired; }
@@ -310,6 +292,19 @@ namespace MediaBrowser.Controller.Entities.TV
Logger.ErrorException("Error in FillMissingEpisodeNumbersFromPath. Episode: {0}", ex, Path ?? Name ?? Id.ToString());
}
+ if (!ParentIndexNumber.HasValue)
+ {
+ var season = Season;
+ if (season != null)
+ {
+ if (season.ParentIndexNumber.HasValue)
+ {
+ ParentIndexNumber = season.ParentIndexNumber;
+ hasChanges = true;
+ }
+ }
+ }
+
return hasChanges;
}
}
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index acd02e8ab..ab125eecb 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities.TV
}
[IgnoreDataMember]
+ public override bool SupportsDateLastMediaAdded
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ [IgnoreDataMember]
public override Guid? DisplayParentId
{
get
@@ -45,27 +54,25 @@ namespace MediaBrowser.Controller.Entities.TV
// Genre, Rating and Stuido will all be the same
protected override IEnumerable<string> GetIndexByOptions()
{
- return new List<string> {
- {"None"},
+ return new List<string> {
+ {"None"},
{"Performer"},
{"Director"},
{"Year"},
};
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- if (Series != null)
+ var list = base.GetUserDataKeys();
+
+ var series = Series;
+ if (series != null)
{
- var seasonNo = IndexNumber ?? 0;
- return Series.GetUserDataKey() + seasonNo.ToString("000");
+ list.InsertRange(0, series.GetUserDataKeys().Select(i => i + (IndexNumber ?? 0).ToString("000")));
}
- return base.CreateUserDataKey();
+ return list;
}
/// <summary>
@@ -94,6 +101,24 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
+ [IgnoreDataMember]
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ if (IndexNumber.HasValue)
+ {
+ var series = Series;
+ if (series != null)
+ {
+ return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000");
+ }
+ }
+
+ return base.PresentationUniqueKey;
+ }
+ }
+
/// <summary>
/// Creates the name of the sort.
/// </summary>
@@ -103,17 +128,23 @@ namespace MediaBrowser.Controller.Entities.TV
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
}
- [IgnoreDataMember]
- public bool IsMissingSeason
+ public override bool RequiresRefresh()
{
- get { return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.IsMissingEpisode); }
+ var result = base.RequiresRefresh();
+
+ if (!result)
+ {
+ if (!IsMissingSeason.HasValue)
+ {
+ return true;
+ }
+ }
+
+ return result;
}
[IgnoreDataMember]
- public bool IsUnaired
- {
- get { return GetEpisodes().All(i => i.IsUnaired); }
- }
+ public bool? IsMissingSeason { get; set; }
[IgnoreDataMember]
public bool IsVirtualUnaired
@@ -124,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.TV
[IgnoreDataMember]
public bool IsMissingOrVirtualUnaired
{
- get { return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); }
+ get { return (IsMissingSeason ?? false) || (LocationType == LocationType.Virtual && IsUnaired); }
}
[IgnoreDataMember]
@@ -135,22 +166,16 @@ namespace MediaBrowser.Controller.Entities.TV
protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query)
{
+ if (query.User == null)
+ {
+ return base.GetItemsInternal(query);
+ }
+
var user = query.User;
Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
- IEnumerable<BaseItem> items;
-
- if (query.User == null)
- {
- items = query.Recursive
- ? GetRecursiveChildren(filter)
- : Children.Where(filter);
- }
- else
- {
- items = GetEpisodes(query.User).Where(filter);
- }
+ var items = GetEpisodes(user).Where(filter);
var result = PostFilterAndSort(items, query);
@@ -171,16 +196,16 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Episode> GetEpisodes(User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
- var episodes = GetRecursiveChildren(user)
- .OfType<Episode>();
-
var series = Series;
if (IndexNumber.HasValue && series != null)
{
- return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes);
+ return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes);
}
+ var episodes = GetRecursiveChildren(user)
+ .OfType<Episode>();
+
if (series != null && series.ContainsEpisodesWithoutSeasonFolders)
{
var seasonNumber = IndexNumber;
@@ -199,7 +224,7 @@ namespace MediaBrowser.Controller.Entities.TV
episodes = list.DistinctBy(i => i.Id);
}
-
+
if (!includeMissingEpisodes)
{
episodes = episodes.Where(i => !i.IsMissingEpisode);
@@ -214,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.TV
.Cast<Episode>();
}
- private IEnumerable<Episode> GetEpisodes()
+ public IEnumerable<Episode> GetEpisodes()
{
var episodes = GetRecursiveChildren().OfType<Episode>();
var series = Series;
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 7eabff072..82ab99980 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MoreLinq;
namespace MediaBrowser.Controller.Entities.TV
{
@@ -47,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
+ [IgnoreDataMember]
+ public override bool SupportsDateLastMediaAdded
+ {
+ get
+ {
+ return true;
+ }
+ }
+
public bool DisplaySpecialsWithSeasons { get; set; }
public List<Guid> LocalTrailerIds { get; set; }
@@ -91,25 +101,40 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
+ [IgnoreDataMember]
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ if (EnablePooling())
+ {
+ return GetUserDataKeys().First();
+ }
+ return base.PresentationUniqueKey;
+ }
+ }
+
/// <summary>
/// Gets the user data key.
/// </summary>
/// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- var key = this.GetProviderId(MetadataProviders.Tvdb);
+ var list = base.GetUserDataKeys();
- if (string.IsNullOrWhiteSpace(key))
+ var key = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(key))
{
- key = this.GetProviderId(MetadataProviders.Imdb);
+ list.Insert(0, key);
}
- if (string.IsNullOrWhiteSpace(key))
+ key = this.GetProviderId(MetadataProviders.Tvdb);
+ if (!string.IsNullOrWhiteSpace(key))
{
- key = base.CreateUserDataKey();
+ list.Insert(0, key);
}
- return key;
+ return list;
}
/// <summary>
@@ -126,8 +151,8 @@ namespace MediaBrowser.Controller.Entities.TV
// Studio, Genre and Rating will all be the same so makes no sense to index by these
protected override IEnumerable<string> GetIndexByOptions()
{
- return new List<string> {
- {"None"},
+ return new List<string> {
+ {"None"},
{"Performer"},
{"Director"},
{"Year"},
@@ -172,7 +197,7 @@ namespace MediaBrowser.Controller.Entities.TV
else
{
items = query.Recursive
- ? GetRecursiveChildren(user, filter)
+ ? GetSeasons(user).Cast<BaseItem>().Concat(GetEpisodes(user)).Where(filter)
: GetSeasons(user).Where(filter);
}
@@ -183,8 +208,35 @@ namespace MediaBrowser.Controller.Entities.TV
public IEnumerable<Season> GetSeasons(User user, bool includeMissingSeasons, bool includeVirtualUnaired)
{
- var seasons = base.GetChildren(user, true)
- .OfType<Season>();
+ IEnumerable<Season> seasons;
+
+ if (EnablePooling())
+ {
+ var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
+ {
+ PresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Series).Name }
+ });
+
+ if (seriesIds.Count > 1)
+ {
+ seasons = LibraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
+ IncludeItemTypes = new[] { typeof(Season).Name },
+ SortBy = new[] { ItemSortBy.SortName }
+
+ }).Cast<Season>();
+ }
+ else
+ {
+ seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
+ }
+ }
+ else
+ {
+ seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType<Season>();
+ }
if (!includeMissingSeasons && !includeVirtualUnaired)
{
@@ -194,7 +246,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
if (!includeMissingSeasons)
{
- seasons = seasons.Where(i => !i.IsMissingSeason);
+ seasons = seasons.Where(i => !(i.IsMissingSeason ?? false));
}
if (!includeVirtualUnaired)
{
@@ -202,9 +254,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- return LibraryManager
- .Sort(seasons, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
- .Cast<Season>();
+ return seasons;
}
public IEnumerable<Episode> GetEpisodes(User user)
@@ -224,17 +274,8 @@ namespace MediaBrowser.Controller.Entities.TV
// Specials could appear twice based on above - once in season 0, once in the aired season
// This depends on settings for that series
// When this happens, remove the duplicate from season 0
- var returnList = new List<Episode>();
- foreach (var episode in allEpisodes)
- {
- if (!returnList.Contains(episode))
- {
- returnList.Insert(0, episode);
- }
- }
-
- return returnList;
+ return allEpisodes.DistinctBy(i => i.Id).Reverse();
}
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
@@ -255,7 +296,7 @@ namespace MediaBrowser.Controller.Entities.TV
// Refresh current item
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
- // Refresh TV
+ // Refresh seasons
foreach (var item in seasons)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -268,12 +309,30 @@ namespace MediaBrowser.Controller.Entities.TV
progress.Report(percent * 100);
}
- // Refresh all non-songs
+ // Refresh episodes and other children
foreach (var item in otherItems)
{
cancellationToken.ThrowIfCancellationRequested();
- await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+ var skipItem = false;
+
+ var episode = item as Episode;
+
+ if (episode != null
+ && refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
+ && !refreshOptions.ReplaceAllMetadata
+ && episode.IsMissingEpisode
+ && episode.LocationType == Model.Entities.LocationType.Virtual
+ && episode.PremiereDate.HasValue
+ && (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
+ {
+ skipItem = true;
+ }
+
+ if (!skipItem)
+ {
+ await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+ }
numComplete++;
double percent = numComplete;
@@ -293,20 +352,46 @@ namespace MediaBrowser.Controller.Entities.TV
return GetEpisodes(user, seasonNumber, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes);
}
- public IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
+ private bool EnablePooling()
{
- return GetEpisodes(user, seasonNumber, includeMissingEpisodes, includeVirtualUnairedEpisodes,
- new List<Episode>());
+ return false;
}
- internal IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> additionalEpisodes)
+ public IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes)
{
- var episodes = GetRecursiveChildren(user, i => i is Episode)
- .Cast<Episode>();
+ IEnumerable<Episode> episodes;
- episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons);
+ if (EnablePooling())
+ {
+ var seriesIds = LibraryManager.GetItemIds(new InternalItemsQuery(user)
+ {
+ PresentationUniqueKey = PresentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Series).Name }
+ });
- episodes = episodes.Concat(additionalEpisodes).Distinct();
+ if (seriesIds.Count > 1)
+ {
+ episodes = LibraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ AncestorIds = seriesIds.Select(i => i.ToString("N")).ToArray(),
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ SortBy = new[] { ItemSortBy.SortName }
+
+ }).Cast<Episode>();
+ }
+ else
+ {
+ episodes = GetRecursiveChildren(user, i => i is Episode)
+ .Cast<Episode>();
+ }
+ }
+ else
+ {
+ episodes = GetRecursiveChildren(user, i => i is Episode)
+ .Cast<Episode>();
+ }
+
+ episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons);
if (!includeMissingEpisodes)
{
@@ -334,7 +419,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
if (!includeSpecials || seasonNumber < 1)
{
- return episodes.Where(i => (i.PhysicalSeasonNumber ?? -1) == seasonNumber);
+ return episodes.Where(i => (i.ParentIndexNumber ?? -1) == seasonNumber);
}
return episodes.Where(i =>
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index fe8bf3ed3..3be2fc624 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -56,26 +56,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The revenue.</value>
public double? Revenue { get; set; }
- protected override string CreateUserDataKey()
- {
- var key = Movie.GetMovieUserDataKey(this);
-
- if (!string.IsNullOrWhiteSpace(key))
- {
- key = key + "-trailer";
-
- // Make sure different trailers have their own data.
- if (RunTimeTicks.HasValue)
- {
- key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
- }
-
- return key;
- }
-
- return base.CreateUserDataKey();
- }
-
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Trailer;
diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs
index 16c37e7d3..f95fd7036 100644
--- a/MediaBrowser.Controller/Entities/UserItemData.cs
+++ b/MediaBrowser.Controller/Entities/UserItemData.cs
@@ -88,6 +88,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The index of the subtitle stream.</value>
public int? SubtitleStreamIndex { get; set; }
+
+ public const double MinLikeValue = 6.5;
/// <summary>
/// This is an interpreted property to indicate likes or dislikes
@@ -101,7 +103,7 @@ namespace MediaBrowser.Controller.Entities
{
if (Rating != null)
{
- return Rating >= 6.5;
+ return Rating >= MinLikeValue;
}
return null;
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 8ce39c697..b9e997d17 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -102,10 +102,5 @@ namespace MediaBrowser.Controller.Entities
LibraryManager.RegisterItem(item);
}
}
-
- public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user)
- {
- // Nothing meaninful here and will only waste resources
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index db669ca37..ba496fa5c 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -348,7 +348,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => !i.IsFolder)
.OfType<IHasAlbumArtist>();
- var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite);
+ var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user, i).IsFavorite);
return GetResult(artists, parent, query);
}
@@ -1077,7 +1077,7 @@ namespace MediaBrowser.Controller.Entities
var e = i as Season;
if (e != null)
{
- return e.IsMissingSeason == val;
+ return (e.IsMissingSeason ?? false) == val;
}
return true;
});
@@ -1218,7 +1218,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsLiked.HasValue)
{
- userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ userData = userData ?? userDataManager.GetUserData(user, item);
if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
{
@@ -1228,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsFavoriteOrLiked.HasValue)
{
- userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ userData = userData ?? userDataManager.GetUserData(user, item);
var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
@@ -1239,7 +1239,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsFavorite.HasValue)
{
- userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ userData = userData ?? userDataManager.GetUserData(user, item);
if (userData.IsFavorite != query.IsFavorite.Value)
{
@@ -1249,7 +1249,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsResumable.HasValue)
{
- userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ userData = userData ?? userDataManager.GetUserData(user, item);
var isResumable = userData.PlaybackPositionTicks > 0;
if (isResumable != query.IsResumable.Value)
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 2c7d3856b..6a9d7cb51 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -28,7 +28,8 @@ namespace MediaBrowser.Controller.Entities
IThemeMedia,
IArchivable
{
- public Guid? PrimaryVersionId { get; set; }
+ [IgnoreDataMember]
+ public string PrimaryVersionId { get; set; }
public List<string> AdditionalParts { get; set; }
public List<string> LocalAlternateVersions { get; set; }
@@ -44,6 +45,20 @@ namespace MediaBrowser.Controller.Entities
}
}
+ [IgnoreDataMember]
+ public override string PresentationUniqueKey
+ {
+ get
+ {
+ if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
+ {
+ return PrimaryVersionId;
+ }
+
+ return base.PresentationUniqueKey;
+ }
+ }
+
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
@@ -56,6 +71,72 @@ namespace MediaBrowser.Controller.Entities
/// <value>The timestamp.</value>
public TransportStreamTimestamp? Timestamp { get; set; }
+ /// <summary>
+ /// Gets or sets the subtitle paths.
+ /// </summary>
+ /// <value>The subtitle paths.</value>
+ public List<string> SubtitleFiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has subtitles.
+ /// </summary>
+ /// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
+ public bool HasSubtitles { get; set; }
+
+ public bool IsPlaceHolder { get; set; }
+ public bool IsShortcut { get; set; }
+ public string ShortcutPath { get; set; }
+
+ /// <summary>
+ /// Gets or sets the video bit rate.
+ /// </summary>
+ /// <value>The video bit rate.</value>
+ public int? VideoBitRate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default index of the video stream.
+ /// </summary>
+ /// <value>The default index of the video stream.</value>
+ public int? DefaultVideoStreamIndex { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type of the video.
+ /// </summary>
+ /// <value>The type of the video.</value>
+ public VideoType VideoType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type of the iso.
+ /// </summary>
+ /// <value>The type of the iso.</value>
+ public IsoType? IsoType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the video3 D format.
+ /// </summary>
+ /// <value>The video3 D format.</value>
+ public Video3DFormat? Video3DFormat { get; set; }
+
+ /// <summary>
+ /// If the video is a folder-rip, this will hold the file list for the largest playlist
+ /// </summary>
+ public List<string> PlayableStreamFileNames { get; set; }
+
+ /// <summary>
+ /// Gets the playable stream files.
+ /// </summary>
+ /// <returns>List{System.String}.</returns>
+ public List<string> GetPlayableStreamFiles()
+ {
+ return GetPlayableStreamFiles(Path);
+ }
+
+ /// <summary>
+ /// Gets or sets the aspect ratio.
+ /// </summary>
+ /// <value>The aspect ratio.</value>
+ public string AspectRatio { get; set; }
+
public Video()
{
PlayableStreamFileNames = new List<string>();
@@ -90,6 +171,14 @@ namespace MediaBrowser.Controller.Entities
{
get
{
+ if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
+ {
+ var item = LibraryManager.GetItemById(PrimaryVersionId) as Video;
+ if (item != null)
+ {
+ return item.MediaSourceCount;
+ }
+ }
return LinkedAlternateVersions.Count + LocalAlternateVersions.Count + 1;
}
}
@@ -131,42 +220,65 @@ namespace MediaBrowser.Controller.Entities
return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
}
- protected override string CreateUserDataKey()
+ [IgnoreDataMember]
+ protected virtual bool EnableDefaultVideoUserDataKeys
{
- if (ExtraType.HasValue)
+ get
{
- var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb);
+ return true;
+ }
+ }
- if (!string.IsNullOrWhiteSpace(key))
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ if (EnableDefaultVideoUserDataKeys)
+ {
+ if (ExtraType.HasValue)
{
- key = key + "-" + ExtraType.ToString().ToLower();
+ var key = this.GetProviderId(MetadataProviders.Tmdb);
+ if (!string.IsNullOrWhiteSpace(key))
+ {
+ list.Insert(0, GetUserDataKey(key));
+ }
- // Make sure different trailers have their own data.
- if (RunTimeTicks.HasValue)
+ key = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(key))
+ {
+ list.Insert(0, GetUserDataKey(key));
+ }
+ }
+ else
+ {
+ var key = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(key))
{
- key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
+ list.Insert(0, key);
}
- return key;
+ key = this.GetProviderId(MetadataProviders.Tmdb);
+ if (!string.IsNullOrWhiteSpace(key))
+ {
+ list.Insert(0, key);
+ }
}
}
- return base.CreateUserDataKey();
+ return list;
}
- /// <summary>
- /// Gets the linked children.
- /// </summary>
- /// <returns>IEnumerable{BaseItem}.</returns>
- public IEnumerable<Video> GetAlternateVersions()
+ private string GetUserDataKey(string providerId)
{
- var filesWithinSameDirectory = GetLocalAlternateVersionIds()
- .Select(i => LibraryManager.GetItemById(i))
- .Where(i => i != null)
- .OfType<Video>();
+ var key = providerId + "-" + ExtraType.ToString().ToLower();
- return filesWithinSameDirectory.Concat(GetLinkedAlternateVersions())
- .OrderBy(i => i.SortName);
+ // Make sure different trailers have their own data.
+ if (RunTimeTicks.HasValue)
+ {
+ key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ return key;
}
public IEnumerable<Video> GetLinkedAlternateVersions()
@@ -193,72 +305,6 @@ namespace MediaBrowser.Controller.Entities
.OrderBy(i => i.SortName);
}
- /// <summary>
- /// Gets or sets the subtitle paths.
- /// </summary>
- /// <value>The subtitle paths.</value>
- public List<string> SubtitleFiles { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has subtitles.
- /// </summary>
- /// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
- public bool HasSubtitles { get; set; }
-
- public bool IsPlaceHolder { get; set; }
- public bool IsShortcut { get; set; }
- public string ShortcutPath { get; set; }
-
- /// <summary>
- /// Gets or sets the video bit rate.
- /// </summary>
- /// <value>The video bit rate.</value>
- public int? VideoBitRate { get; set; }
-
- /// <summary>
- /// Gets or sets the default index of the video stream.
- /// </summary>
- /// <value>The default index of the video stream.</value>
- public int? DefaultVideoStreamIndex { get; set; }
-
- /// <summary>
- /// Gets or sets the type of the video.
- /// </summary>
- /// <value>The type of the video.</value>
- public VideoType VideoType { get; set; }
-
- /// <summary>
- /// Gets or sets the type of the iso.
- /// </summary>
- /// <value>The type of the iso.</value>
- public IsoType? IsoType { get; set; }
-
- /// <summary>
- /// Gets or sets the video3 D format.
- /// </summary>
- /// <value>The video3 D format.</value>
- public Video3DFormat? Video3DFormat { get; set; }
-
- /// <summary>
- /// If the video is a folder-rip, this will hold the file list for the largest playlist
- /// </summary>
- public List<string> PlayableStreamFileNames { get; set; }
-
- /// <summary>
- /// Gets the playable stream files.
- /// </summary>
- /// <returns>List{System.String}.</returns>
- public List<string> GetPlayableStreamFiles()
- {
- return GetPlayableStreamFiles(Path);
- }
-
- /// <summary>
- /// Gets or sets the aspect ratio.
- /// </summary>
- /// <value>The aspect ratio.</value>
- public string AspectRatio { get; set; }
-
[IgnoreDataMember]
public override string ContainingFolderPath
{
@@ -317,6 +363,11 @@ namespace MediaBrowser.Controller.Entities
{
return false;
}
+
+ if (newAsVideo.VideoType != VideoType)
+ {
+ return false;
+ }
}
return base.IsValidFromResolver(newItem);
@@ -463,6 +514,36 @@ namespace MediaBrowser.Controller.Entities
}).FirstOrDefault();
}
+ private List<Tuple<Video, MediaSourceType>> GetAllVideosForMediaSources()
+ {
+ var list = new List<Tuple<Video, MediaSourceType>>();
+
+ list.Add(new Tuple<Video, MediaSourceType>(this, MediaSourceType.Default));
+ list.AddRange(GetLinkedAlternateVersions().Select(i => new Tuple<Video, MediaSourceType>(i, MediaSourceType.Grouping)));
+
+ if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
+ {
+ var primary = LibraryManager.GetItemById(PrimaryVersionId) as Video;
+ if (primary != null)
+ {
+ var existingIds = list.Select(i => i.Item1.Id).ToList();
+ list.Add(new Tuple<Video, MediaSourceType>(primary, MediaSourceType.Grouping));
+ list.AddRange(primary.GetLinkedAlternateVersions().Where(i => !existingIds.Contains(i.Id)).Select(i => new Tuple<Video, MediaSourceType>(i, MediaSourceType.Grouping)));
+ }
+ }
+
+ var localAlternates = list
+ .SelectMany(i => i.Item1.GetLocalAlternateVersionIds())
+ .Select(LibraryManager.GetItemById)
+ .Where(i => i != null)
+ .OfType<Video>()
+ .ToList();
+
+ list.AddRange(localAlternates.Select(i => new Tuple<Video, MediaSourceType>(i, MediaSourceType.Default)));
+
+ return list;
+ }
+
public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
if (SourceType == SourceType.Channel)
@@ -481,13 +562,8 @@ namespace MediaBrowser.Controller.Entities
};
}
- var item = this;
-
- var result = item.GetAlternateVersions()
- .Select(i => GetVersionInfo(enablePathSubstitution, i, MediaSourceType.Grouping))
- .ToList();
-
- result.Add(GetVersionInfo(enablePathSubstitution, item, MediaSourceType.Default));
+ var list = GetAllVideosForMediaSources();
+ var result = list.Select(i => GetVersionInfo(enablePathSubstitution, i.Item1, i.Item2)).ToList();
return result.OrderBy(i =>
{
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 163dcd667..db896f1fc 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -11,13 +11,12 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Year : BaseItem, IItemByName
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return "Year-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "Year-" + Name);
+ return list;
}
/// <summary>
@@ -71,6 +70,22 @@ namespace MediaBrowser.Controller.Entities
return inputItems.Where(i => i.ProductionYear.HasValue && i.ProductionYear.Value == year);
}
+ public IEnumerable<BaseItem> GetTaggedItems(InternalItemsQuery query)
+ {
+ int year;
+
+ var usCulture = new CultureInfo("en-US");
+
+ if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out year))
+ {
+ return new List<BaseItem>();
+ }
+
+ query.Years = new[] { year };
+
+ return LibraryManager.GetItemList(query);
+ }
+
public int? GetYearValue()
{
int i;
diff --git a/MediaBrowser.Controller/Health/IHealthMonitor.cs b/MediaBrowser.Controller/Health/IHealthMonitor.cs
new file mode 100644
index 000000000..b8ad98fc1
--- /dev/null
+++ b/MediaBrowser.Controller/Health/IHealthMonitor.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Notifications;
+
+namespace MediaBrowser.Controller.Health
+{
+ public interface IHealthMonitor
+ {
+ Task<List<Notification>> GetNotifications(CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index e4eecec18..65eed1a23 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller
public interface IServerApplicationHost : IApplicationHost
{
event EventHandler HasUpdateAvailableChanged;
-
+
/// <summary>
/// Gets the system info.
/// </summary>
@@ -86,5 +86,7 @@ namespace MediaBrowser.Controller
/// <param name="ipAddress">The ip address.</param>
/// <returns>System.String.</returns>
string GetLocalApiUrl(IPAddress ipAddress);
+
+ void LaunchUrl(string url);
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index c8b3d5131..936b97c6e 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="fileInfo">The file information.</param>
/// <param name="parent">The parent.</param>
/// <returns>BaseItem.</returns>
- BaseItem ResolvePath(FileSystemMetadata fileInfo,
+ BaseItem ResolvePath(FileSystemMetadata fileInfo,
Folder parent = null);
/// <summary>
@@ -36,9 +36,9 @@ namespace MediaBrowser.Controller.Library
/// <param name="parent">The parent.</param>
/// <param name="collectionType">Type of the collection.</param>
/// <returns>List{``0}.</returns>
- IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
+ IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
IDirectoryService directoryService,
- Folder parent, string
+ Folder parent, string
collectionType = null);
/// <summary>
@@ -59,8 +59,8 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="path">The path.</param>
/// <returns>BaseItem.</returns>
- BaseItem FindByPath(string path);
-
+ BaseItem FindByPath(string path, bool? isFolder);
+
/// <summary>
/// Gets the artist.
/// </summary>
@@ -156,7 +156,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="id">The identifier.</param>
/// <returns>BaseItem.</returns>
BaseItem GetMemoryItemById(Guid id);
-
+
/// <summary>
/// Gets the intros.
/// </summary>
@@ -243,6 +243,8 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns>
BaseItem RetrieveItem(Guid id);
+ bool IsScanRunning { get; }
+
/// <summary>
/// Occurs when [item added].
/// </summary>
@@ -290,7 +292,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="path">The path.</param>
/// <returns>System.String.</returns>
string GetConfiguredContentType(string path);
-
+
/// <summary>
/// Normalizes the root path list.
/// </summary>
@@ -332,8 +334,8 @@ namespace MediaBrowser.Controller.Library
Task<UserView> GetNamedView(User user,
string name,
string parentId,
- string viewType,
- string sortName,
+ string viewType,
+ string sortName,
CancellationToken cancellationToken);
/// <summary>
@@ -346,8 +348,8 @@ namespace MediaBrowser.Controller.Library
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;UserView&gt;.</returns>
Task<UserView> GetNamedView(User user,
- string name,
- string viewType,
+ string name,
+ string viewType,
string sortName,
CancellationToken cancellationToken);
@@ -393,7 +395,7 @@ namespace MediaBrowser.Controller.Library
string viewType,
string sortName,
CancellationToken cancellationToken);
-
+
/// <summary>
/// Determines whether [is video file] [the specified path].
/// </summary>
@@ -477,14 +479,14 @@ namespace MediaBrowser.Controller.Library
/// <param name="query">The query.</param>
/// <returns>List&lt;PersonInfo&gt;.</returns>
List<PersonInfo> GetPeople(InternalPeopleQuery query);
-
+
/// <summary>
/// Gets the people items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>List&lt;Person&gt;.</returns>
List<Person> GetPeopleItems(InternalPeopleQuery query);
-
+
/// <summary>
/// Gets all people names.
/// </summary>
@@ -559,7 +561,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query);
-
+
/// <summary>
/// Ignores the file.
/// </summary>
@@ -567,5 +569,10 @@ namespace MediaBrowser.Controller.Library
/// <param name="parent">The parent.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
+
+ void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, bool refreshLibrary);
+ void RemoveVirtualFolder(string name, bool refreshLibrary);
+ void AddMediaPath(string virtualFolderName, string path);
+ void RemoveMediaPath(string virtualFolderName, string path);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index 56ac14e9d..e2358650b 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -29,21 +29,10 @@ namespace MediaBrowser.Controller.Library
/// <returns>Task.</returns>
Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
- /// <summary>
- /// Gets the user data.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
- /// <returns>Task{UserItemData}.</returns>
- UserItemData GetUserData(string userId, string key);
+ UserItemData GetUserData(IHasUserData user, IHasUserData item);
- /// <summary>
- /// Gets the user data.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
- /// <returns>Task{UserItemData}.</returns>
- UserItemData GetUserData(Guid userId, string key);
+ UserItemData GetUserData(string userId, IHasUserData item);
+ UserItemData GetUserData(Guid userId, IHasUserData item);
/// <summary>
/// Gets the user data dto.
diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs
index f8039b2cf..29421ebaf 100644
--- a/MediaBrowser.Controller/Library/TVUtils.cs
+++ b/MediaBrowser.Controller/Library/TVUtils.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// The banner URL
/// </summary>
- public static readonly string BannerUrl = "http://www.thetvdb.com/banners/";
+ public static readonly string BannerUrl = "https://www.thetvdb.com/banners/";
/// <summary>
/// Gets the air days.
diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
index ba328ff75..654c6b581 100644
--- a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
+++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using System;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.Library
{
@@ -15,11 +16,7 @@ namespace MediaBrowser.Controller.Library
/// <value>The user id.</value>
public Guid UserId { get; set; }
- /// <summary>
- /// Gets or sets the key.
- /// </summary>
- /// <value>The key.</value>
- public string Key { get; set; }
+ public List<string> Keys { get; set; }
/// <summary>
/// Gets or sets the save reason.
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index 498602ddf..1e7aa3de5 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -46,6 +46,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
+
+ string ApplyDuration(string streamPath, TimeSpan duration);
}
public interface IConfigurableTunerHost
{
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
index 17a27eac1..e6f472414 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -46,17 +46,6 @@ namespace MediaBrowser.Controller.LiveTv
}
/// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
- {
- var name = GetClientTypeName();
-
- return name + "-" + Name + (EpisodeTitle ?? string.Empty);
- }
-
- /// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>
/// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 35b9a1959..50aeed27d 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -11,13 +11,12 @@ namespace MediaBrowser.Controller.LiveTv
{
public class LiveTvChannel : BaseItem, IHasMediaSources
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- return GetClientTypeName() + "-" + Name;
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, GetClientTypeName() + "-" + Name);
+ return list;
}
public override UnratedItem GetBlockUnratedType()
@@ -45,6 +44,15 @@ namespace MediaBrowser.Controller.LiveTv
set { }
}
+ [IgnoreDataMember]
+ public override bool EnableRememberingTrackSelections
+ {
+ get
+ {
+ return false;
+ }
+ }
+
/// <summary>
/// Gets or sets the number.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 59b921c6a..cc30709db 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -4,36 +4,40 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.LiveTv;
using System;
+using System.Collections.Generic;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.LiveTv
{
public class LiveTvProgram : BaseItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes
{
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
+ public override List<string> GetUserDataKeys()
{
- if (IsMovie)
+ var list = base.GetUserDataKeys();
+
+ if (!IsSeries)
{
- var key = Movie.GetMovieUserDataKey(this);
+ var key = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrWhiteSpace(key))
+ {
+ list.Insert(0, key);
+ }
+ key = this.GetProviderId(MetadataProviders.Tmdb);
if (!string.IsNullOrWhiteSpace(key))
{
- return key;
+ list.Insert(0, key);
}
}
-
- if (IsSeries && !string.IsNullOrWhiteSpace(EpisodeTitle))
+ else if (!string.IsNullOrWhiteSpace(EpisodeTitle))
{
var name = GetClientTypeName();
- return name + "-" + Name + (EpisodeTitle ?? string.Empty);
+ list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty));
}
- return base.CreateUserDataKey();
+ return list;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index f310a957c..a8c737673 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -45,32 +45,6 @@ namespace MediaBrowser.Controller.LiveTv
set { }
}
- /// <summary>
- /// Gets the user data key.
- /// </summary>
- /// <returns>System.String.</returns>
- protected override string CreateUserDataKey()
- {
- if (IsMovie)
- {
- var key = Movie.GetMovieUserDataKey(this);
-
- if (!string.IsNullOrWhiteSpace(key))
- {
- return key;
- }
- }
-
- if (IsSeries && !string.IsNullOrWhiteSpace(EpisodeTitle))
- {
- var name = GetClientTypeName();
-
- return name + "-" + Name + (EpisodeTitle ?? string.Empty);
- }
-
- return base.CreateUserDataKey();
- }
-
[IgnoreDataMember]
public override string MediaType
{
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 6ff4e39e2..bc28ec015 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -180,6 +180,7 @@
<Compile Include="Entities\UserView.cs" />
<Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
+ <Compile Include="Health\IHealthMonitor.cs" />
<Compile Include="IO\ThrottledStream.cs" />
<Compile Include="Library\DeleteOptions.cs" />
<Compile Include="Library\ILibraryPostScanTask.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index d2feb4116..7c3959f6e 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -4,13 +4,14 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Controller.MediaEncoding
{
/// <summary>
/// Interface IMediaEncoder
/// </summary>
- public interface IMediaEncoder
+ public interface IMediaEncoder : ITranscoderSupport
{
/// <summary>
/// Gets the encoder path.
diff --git a/MediaBrowser.Controller/Notifications/INotificationsRepository.cs b/MediaBrowser.Controller/Notifications/INotificationsRepository.cs
index 6ad4a5377..cd587a509 100644
--- a/MediaBrowser.Controller/Notifications/INotificationsRepository.cs
+++ b/MediaBrowser.Controller/Notifications/INotificationsRepository.cs
@@ -19,12 +19,6 @@ namespace MediaBrowser.Controller.Notifications
/// Occurs when [notifications marked read].
/// </summary>
event EventHandler<NotificationReadEventArgs> NotificationsMarkedRead;
-
- /// <summary>
- /// Opens the connection to the repository
- /// </summary>
- /// <returns>Task.</returns>
- Task Initialize();
/// <summary>
/// Gets the notifications.
diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
index 17de730cb..abf96994f 100644
--- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
@@ -12,12 +12,6 @@ namespace MediaBrowser.Controller.Persistence
public interface IDisplayPreferencesRepository : IRepository
{
/// <summary>
- /// Opens the connection to the repository
- /// </summary>
- /// <returns>Task.</returns>
- Task Initialize();
-
- /// <summary>
/// Saves display preferences for an item
/// </summary>
/// <param name="displayPreferences">The display preferences.</param>
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 15df1f649..7bcc36958 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -14,12 +14,6 @@ namespace MediaBrowser.Controller.Persistence
public interface IItemRepository : IRepository
{
/// <summary>
- /// Opens the connection to the repository
- /// </summary>
- /// <returns>Task.</returns>
- Task Initialize();
-
- /// <summary>
/// Saves an item
/// </summary>
/// <param name="item">The item.</param>
diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
index 2a904be0d..2e165f416 100644
--- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
@@ -12,12 +12,6 @@ namespace MediaBrowser.Controller.Persistence
public interface IUserDataRepository : IRepository
{
/// <summary>
- /// Opens the connection to the repository
- /// </summary>
- /// <returns>Task.</returns>
- Task Initialize();
-
- /// <summary>
/// Saves the user data.
/// </summary>
/// <param name="userId">The user id.</param>
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index 0f9af6550..67b1d479b 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Playlists
{
@@ -38,6 +39,15 @@ namespace MediaBrowser.Controller.Playlists
}
}
+ [IgnoreDataMember]
+ public override bool SupportsCumulativeRunTimeTicks
+ {
+ get
+ {
+ return true;
+ }
+ }
+
public override bool IsAuthorizedToDelete(User user)
{
return true;
@@ -50,12 +60,12 @@ namespace MediaBrowser.Controller.Playlists
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
- return GetPlayableItems(user);
+ return GetPlayableItems(user).Result;
}
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
{
- var items = GetPlayableItems(user);
+ var items = GetPlayableItems(user).Result;
if (filter != null)
{
@@ -70,32 +80,40 @@ namespace MediaBrowser.Controller.Playlists
return GetLinkedChildrenInfos();
}
- private IEnumerable<BaseItem> GetPlayableItems(User user)
+ private Task<IEnumerable<BaseItem>> GetPlayableItems(User user)
{
return GetPlaylistItems(MediaType, base.GetChildren(user, true), user);
}
- public static IEnumerable<BaseItem> GetPlaylistItems(string playlistMediaType, IEnumerable<BaseItem> inputItems, User user)
+ public static async Task<IEnumerable<BaseItem>> GetPlaylistItems(string playlistMediaType, IEnumerable<BaseItem> inputItems, User user)
{
if (user != null)
{
inputItems = inputItems.Where(i => i.IsVisible(user));
}
- return inputItems.SelectMany(i => GetPlaylistItems(i, user))
- .Where(m => string.Equals(m.MediaType, playlistMediaType, StringComparison.OrdinalIgnoreCase));
+ var list = new List<BaseItem>();
+
+ foreach (var item in inputItems)
+ {
+ var playlistItems = await GetPlaylistItems(item, user, playlistMediaType).ConfigureAwait(false);
+ list.AddRange(playlistItems);
+ }
+
+ return list;
}
- private static IEnumerable<BaseItem> GetPlaylistItems(BaseItem item, User user)
+ private static async Task<IEnumerable<BaseItem>> GetPlaylistItems(BaseItem item, User user, string mediaType)
{
var musicGenre = item as MusicGenre;
if (musicGenre != null)
{
- Func<BaseItem, bool> filter = i => i is Audio && i.Genres.Contains(musicGenre.Name, StringComparer.OrdinalIgnoreCase);
-
- var items = user == null
- ? LibraryManager.RootFolder.GetRecursiveChildren(filter)
- : user.RootFolder.GetRecursiveChildren(user, filter);
+ var items = LibraryManager.GetItemList(new InternalItemsQuery(user)
+ {
+ Recursive = true,
+ IncludeItemTypes = new[] { typeof(Audio).Name },
+ Genres = new[] { musicGenre.Name }
+ });
return LibraryManager.Sort(items, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending);
}
@@ -119,15 +137,19 @@ namespace MediaBrowser.Controller.Playlists
var folder = item as Folder;
if (folder != null)
{
- var items = user == null
- ? folder.GetRecursiveChildren(m => !m.IsFolder)
- : folder.GetRecursiveChildren(user, m => !m.IsFolder);
-
- if (folder.IsPreSorted)
+ var query = new InternalItemsQuery(user)
{
- return items;
- }
- return LibraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending);
+ Recursive = true,
+ IsFolder = false,
+ SortBy = new[] { ItemSortBy.SortName },
+ MediaTypes = new[] { mediaType },
+ EnableTotalRecordCount = false
+ };
+
+ var itemsResult = await folder.GetItems(query).ConfigureAwait(false);
+ var items = itemsResult.Items;
+
+ return items;
}
return new[] { item };
diff --git a/MediaBrowser.Controller/Providers/IProviderRepository.cs b/MediaBrowser.Controller/Providers/IProviderRepository.cs
index 1f77d0ca1..891275d77 100644
--- a/MediaBrowser.Controller/Providers/IProviderRepository.cs
+++ b/MediaBrowser.Controller/Providers/IProviderRepository.cs
@@ -21,11 +21,5 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken);
-
- /// <summary>
- /// Initializes this instance.
- /// </summary>
- /// <returns>Task.</returns>
- Task Initialize();
}
}
diff --git a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
index 21289970e..093b37df3 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Dlna.ContentDirectory
{
@@ -27,6 +28,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
private readonly IChannelManager _channelManager;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IUserViewManager _userViewManager;
+ private readonly Func<IMediaEncoder> _mediaEncoder;
public ContentDirectory(IDlnaManager dlna,
IUserDataManager userDataManager,
@@ -35,7 +37,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
IServerConfigurationManager config,
IUserManager userManager,
ILogger logger,
- IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
+ IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder)
: base(logger, httpClient)
{
_dlna = dlna;
@@ -48,6 +50,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
_channelManager = channelManager;
_mediaSourceManager = mediaSourceManager;
_userViewManager = userViewManager;
+ _mediaEncoder = mediaEncoder;
}
private int SystemUpdateId
@@ -89,7 +92,8 @@ namespace MediaBrowser.Dlna.ContentDirectory
_localization,
_channelManager,
_mediaSourceManager,
- _userViewManager)
+ _userViewManager,
+ _mediaEncoder())
.ProcessControlRequest(request);
}
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 01c7c33b6..bc9fa1d7e 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -23,6 +23,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Dlna.ContentDirectory
{
@@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
private readonly IServerConfigurationManager _config;
private readonly User _user;
private readonly IUserViewManager _userViewManager;
+ private readonly IMediaEncoder _mediaEncoder;
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
@@ -47,7 +49,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
private readonly DeviceProfile _profile;
- public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager)
+ public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder)
: base(config, logger)
{
_libraryManager = libraryManager;
@@ -56,10 +58,11 @@ namespace MediaBrowser.Dlna.ContentDirectory
_systemUpdateId = systemUpdateId;
_channelManager = channelManager;
_userViewManager = userViewManager;
+ _mediaEncoder = mediaEncoder;
_profile = profile;
_config = config;
- _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager);
+ _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, _mediaEncoder);
}
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
@@ -108,7 +111,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 89d00eb32..af833a85c 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -19,6 +19,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Dlna.Didl
@@ -42,8 +43,9 @@ namespace MediaBrowser.Dlna.Didl
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
+ private readonly IMediaEncoder _mediaEncoder;
- public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager)
+ public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
{
_profile = profile;
_imageProcessor = imageProcessor;
@@ -53,6 +55,7 @@ namespace MediaBrowser.Dlna.Didl
_mediaSourceManager = mediaSourceManager;
_logger = logger;
_libraryManager = libraryManager;
+ _mediaEncoder = mediaEncoder;
_accessToken = accessToken;
_user = user;
}
@@ -142,7 +145,7 @@ namespace MediaBrowser.Dlna.Didl
{
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
- streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
+ streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
{
ItemId = GetClientId(video),
MediaSources = sources,
@@ -385,7 +388,7 @@ namespace MediaBrowser.Dlna.Didl
{
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
- streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
+ streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
{
ItemId = GetClientId(audio),
MediaSources = sources,
diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
index 5e8be1c4c..dfec8baaa 100644
--- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
+++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Dlna.Ssdp;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Dlna.Main
{
@@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.Main
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly IMediaEncoder _mediaEncoder;
private readonly SsdpHandler _ssdpHandler;
private readonly IDeviceDiscovery _deviceDiscovery;
@@ -55,7 +57,7 @@ namespace MediaBrowser.Dlna.Main
IUserDataManager userDataManager,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
- ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery)
+ ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder)
{
_config = config;
_appHost = appHost;
@@ -70,6 +72,7 @@ namespace MediaBrowser.Dlna.Main
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_deviceDiscovery = deviceDiscovery;
+ _mediaEncoder = mediaEncoder;
_ssdpHandler = (SsdpHandler)ssdpHandler;
_logger = logManager.GetLogger("Dlna");
}
@@ -239,7 +242,8 @@ namespace MediaBrowser.Dlna.Main
_config,
_userDataManager,
_localization,
- _mediaSourceManager);
+ _mediaSourceManager,
+ _mediaEncoder);
_manager.Start();
}
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index db5e0ee29..80bb756ef 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -18,6 +18,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Dlna.PlayTo
{
@@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IConfigurationManager _config;
+ private readonly IMediaEncoder _mediaEncoder;
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
@@ -74,7 +76,7 @@ namespace MediaBrowser.Dlna.PlayTo
get { return IsSessionActive; }
}
- public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config)
+ public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
{
_session = session;
_sessionManager = sessionManager;
@@ -88,6 +90,7 @@ namespace MediaBrowser.Dlna.PlayTo
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_config = config;
+ _mediaEncoder = mediaEncoder;
_accessToken = accessToken;
_logger = logger;
_creationTime = DateTime.UtcNow;
@@ -478,7 +481,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
- var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager)
+ var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder)
.GetItemDidl(_config.GetDlnaConfiguration(), item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
playlistItem.Didl = itemXml;
@@ -550,7 +553,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
return new PlaylistItem
{
- StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
+ StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
{
ItemId = item.Id.ToString("N"),
MediaSources = mediaSources,
@@ -570,7 +573,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
return new PlaylistItem
{
- StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
+ StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
{
ItemId = item.Id.ToString("N"),
MediaSources = mediaSources,
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index 18daef331..bbb9bf6de 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
+using MediaBrowser.Controller.MediaEncoding;
namespace MediaBrowser.Dlna.PlayTo
{
@@ -32,11 +33,12 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly IMediaSourceManager _mediaSourceManager;
+ private readonly IMediaEncoder _mediaEncoder;
private readonly List<string> _nonRendererUrls = new List<string>();
private DateTime _lastRendererClear;
- public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
+ public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@@ -51,6 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
+ _mediaEncoder = mediaEncoder;
}
public void Start()
@@ -132,7 +135,8 @@ namespace MediaBrowser.Dlna.PlayTo
_userDataManager,
_localization,
_mediaSourceManager,
- _config);
+ _config,
+ _mediaEncoder);
controller.Init(device);
diff --git a/MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs b/MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
index a9af85346..8f3ad82ba 100644
--- a/MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
@@ -1,5 +1,5 @@
-using System.Xml.Serialization;
-using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dlna;
+using System.Xml.Serialization;
namespace MediaBrowser.Dlna.Profiles
{
@@ -10,8 +10,6 @@ namespace MediaBrowser.Dlna.Profiles
{
Name = "BubbleUPnp";
- TimelineOffsetSeconds = 5;
-
Identification = new DeviceIdentification
{
ModelName = "BubbleUPnp",
@@ -27,16 +25,18 @@ namespace MediaBrowser.Dlna.Profiles
new TranscodingProfile
{
Container = "mp3",
- Type = DlnaProfileType.Audio,
- AudioCodec = "mp3"
+ AudioCodec = "mp3",
+ Type = DlnaProfileType.Audio
},
+
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
- VideoCodec = "h264",
- AudioCodec = "aac"
+ AudioCodec = "aac",
+ VideoCodec = "h264"
},
+
new TranscodingProfile
{
Container = "jpeg",
@@ -48,21 +48,20 @@ namespace MediaBrowser.Dlna.Profiles
{
new DirectPlayProfile
{
- Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+ Container = "",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
- Container = "mp3,flac,asf,off,oga,aac",
+ Container = "",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
+ Container = "",
Type = DlnaProfileType.Photo,
-
- Container = "jpeg,png,gif,bmp,tiff"
}
};
@@ -71,6 +70,77 @@ namespace MediaBrowser.Dlna.Profiles
ContainerProfiles = new ContainerProfile[] { };
CodecProfiles = new CodecProfile[] { };
+
+ SubtitleProfiles = new[]
+ {
+ new SubtitleProfile
+ {
+ Format = "srt",
+ Method = SubtitleDeliveryMethod.External,
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.External,
+ },
+
+ new SubtitleProfile
+ {
+ Format = "srt",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ass",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ssa",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "smi",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "dvdsub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgs",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgssub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ }
+ };
}
}
}
diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
index 386a4eb1e..76797c0e3 100644
--- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs
@@ -30,8 +30,8 @@ namespace MediaBrowser.Dlna.Profiles
MaxIconWidth = 48;
MaxIconHeight = 48;
- MaxStreamingBitrate = 15000000;
- MaxStaticBitrate = 15000000;
+ MaxStreamingBitrate = 20000000;
+ MaxStaticBitrate = 20000000;
MusicStreamingTranscodingBitrate = 192000;
MusicSyncBitrate = 192000;
diff --git a/MediaBrowser.Dlna/Profiles/VlcProfile.cs b/MediaBrowser.Dlna/Profiles/VlcProfile.cs
index 5b3f7c0d1..09d290f3a 100644
--- a/MediaBrowser.Dlna/Profiles/VlcProfile.cs
+++ b/MediaBrowser.Dlna/Profiles/VlcProfile.cs
@@ -1,5 +1,5 @@
-using System.Xml.Serialization;
-using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dlna;
+using System.Xml.Serialization;
namespace MediaBrowser.Dlna.Profiles
{
@@ -10,6 +10,7 @@ namespace MediaBrowser.Dlna.Profiles
{
Name = "Vlc";
+
TimelineOffsetSeconds = 5;
Identification = new DeviceIdentification
@@ -27,16 +28,18 @@ namespace MediaBrowser.Dlna.Profiles
new TranscodingProfile
{
Container = "mp3",
- Type = DlnaProfileType.Audio,
- AudioCodec = "mp3"
+ AudioCodec = "mp3",
+ Type = DlnaProfileType.Audio
},
+
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
- VideoCodec = "h264",
- AudioCodec = "aac"
+ AudioCodec = "aac",
+ VideoCodec = "h264"
},
+
new TranscodingProfile
{
Container = "jpeg",
@@ -48,21 +51,20 @@ namespace MediaBrowser.Dlna.Profiles
{
new DirectPlayProfile
{
- Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+ Container = "",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
- Container = "mp3,flac,asf,off,oga,aac",
+ Container = "",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
+ Container = "",
Type = DlnaProfileType.Photo,
-
- Container = "jpeg,png,gif,bmp,tiff"
}
};
@@ -71,6 +73,77 @@ namespace MediaBrowser.Dlna.Profiles
ContainerProfiles = new ContainerProfile[] { };
CodecProfiles = new CodecProfile[] { };
+
+ SubtitleProfiles = new[]
+ {
+ new SubtitleProfile
+ {
+ Format = "srt",
+ Method = SubtitleDeliveryMethod.External,
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.External,
+ },
+
+ new SubtitleProfile
+ {
+ Format = "srt",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ass",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "ssa",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "smi",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "dvdsub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgs",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "pgssub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ },
+
+ new SubtitleProfile
+ {
+ Format = "sub",
+ Method = SubtitleDeliveryMethod.Embed,
+ DidlMode = "",
+ }
+ };
}
}
}
diff --git a/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml b/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
index 2b67b0eaf..38b741454 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
@@ -22,30 +22,41 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
<ProtocolInfo>http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_50_AC3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_BASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_FULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-matroska:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_1080i_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_HP_HD_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_LPCM;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_ASP_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_SP_L6_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_NDSD;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_LPCM_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000</ProtocolInfo>
- <TimelineOffsetSeconds>5</TimelineOffsetSeconds>
+ <TimelineOffsetSeconds>0</TimelineOffsetSeconds>
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
<RequiresPlainFolders>false</RequiresPlainFolders>
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso" type="Video" />
- <DirectPlayProfile container="mp3,flac,asf,off,oga,aac" type="Audio" />
- <DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
+ <DirectPlayProfile container="" type="Video" />
+ <DirectPlayProfile container="" type="Audio" />
+ <DirectPlayProfile container="" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
<ResponseProfiles />
- <SubtitleProfiles />
+ <SubtitleProfiles>
+ <SubtitleProfile format="srt" method="External" />
+ <SubtitleProfile format="sub" method="External" />
+ <SubtitleProfile format="srt" method="Embed" didlMode="" />
+ <SubtitleProfile format="ass" method="Embed" didlMode="" />
+ <SubtitleProfile format="ssa" method="Embed" didlMode="" />
+ <SubtitleProfile format="smi" method="Embed" didlMode="" />
+ <SubtitleProfile format="dvdsub" method="Embed" didlMode="" />
+ <SubtitleProfile format="pgs" method="Embed" didlMode="" />
+ <SubtitleProfile format="pgssub" method="Embed" didlMode="" />
+ <SubtitleProfile format="sub" method="Embed" didlMode="" />
+ </SubtitleProfiles>
</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml
index 779c800e5..9364f464b 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Default.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml
@@ -16,8 +16,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -33,9 +33,9 @@
<DirectPlayProfile container="avi,mp4" type="Video" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
index 89f6c03c7..5b8ff5d68 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
@@ -21,8 +21,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -37,9 +37,9 @@
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml b/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
index 437e6bdb4..561abe0e5 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -39,8 +39,8 @@
<DirectPlayProfile container="jpeg,jpg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mpeg" type="Video" videoCodec="mpeg2video" audioCodec="mp2" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mpeg" type="Video" videoCodec="mpeg2video" audioCodec="mp2" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles>
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
index 62cc5d81e..b2d267657 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -43,9 +43,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="mp4" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="mp4" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles>
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml
index 73cb54c70..d0985e135 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml
@@ -40,9 +40,9 @@
<DirectPlayProfile container="" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
index 9649b5e68..404bbbb20 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -42,9 +42,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
index 102e05d93..1e6db99b1 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
@@ -20,8 +20,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -37,9 +37,9 @@
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml b/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
index 588752d91..679aa26bd 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -43,9 +43,9 @@
<DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
index 20a112b67..256443093 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -50,9 +50,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
index b6b420ba2..3d50b1724 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
@@ -16,8 +16,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -38,9 +38,9 @@
<DirectPlayProfile container="jpeg,gif,bmp,png" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="mp4" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="mp4" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles>
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
index 1f3692322..b09c25afa 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -50,9 +50,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
index 673affa70..49f4759b9 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -48,9 +48,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
index 8780229c5..41a996b66 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
@@ -24,8 +24,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -47,9 +47,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="mpeg2video" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="mpeg2video" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
index 1ea6276f8..ed66118d3 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -45,9 +45,9 @@
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
index 012b6ca73..88ff6047f 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -48,9 +48,9 @@
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
index 52a3e196c..fb06ab0ac 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -50,9 +50,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
index f060f6ef4..67526f5f2 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -55,9 +55,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml
index de418f8be..850237756 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -55,9 +55,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
index f147d75b6..11dc33239 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -45,9 +45,9 @@
<DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac,mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac,mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml
index bc83d488e..5a763006b 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -45,9 +45,9 @@
<DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml b/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
index 69ee8a002..a007a4aa3 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -35,17 +35,28 @@
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
<XmlRootAttributes />
<DirectPlayProfiles>
- <DirectPlayProfile container="avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso" type="Video" />
- <DirectPlayProfile container="mp3,flac,asf,off,oga,aac" type="Audio" />
- <DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
+ <DirectPlayProfile container="" type="Video" />
+ <DirectPlayProfile container="" type="Audio" />
+ <DirectPlayProfile container="" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
<ResponseProfiles />
- <SubtitleProfiles />
+ <SubtitleProfiles>
+ <SubtitleProfile format="srt" method="External" />
+ <SubtitleProfile format="sub" method="External" />
+ <SubtitleProfile format="srt" method="Embed" didlMode="" />
+ <SubtitleProfile format="ass" method="Embed" didlMode="" />
+ <SubtitleProfile format="ssa" method="Embed" didlMode="" />
+ <SubtitleProfile format="smi" method="Embed" didlMode="" />
+ <SubtitleProfile format="dvdsub" method="Embed" didlMode="" />
+ <SubtitleProfile format="pgs" method="Embed" didlMode="" />
+ <SubtitleProfile format="pgssub" method="Embed" didlMode="" />
+ <SubtitleProfile format="sub" method="Embed" didlMode="" />
+ </SubtitleProfiles>
</Profile> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
index 2c812f98c..6f245202d 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -51,9 +51,9 @@
<DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Photo">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
index 9dbefc0e4..bb937101d 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
@@ -24,8 +24,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -46,9 +46,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="asf" type="Video" videoCodec="wmv2" audioCodec="wmav2" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Bytes" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="asf" type="Video" videoCodec="wmv2" audioCodec="wmav2" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Bytes" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Video" container="mp4,mov">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
index ad08adf0d..381676944 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
@@ -23,8 +23,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -46,9 +46,9 @@
<DirectPlayProfile container="jpeg" type="Photo" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" videoCodec="jpeg" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" videoCodec="jpeg" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles>
<ContainerProfile type="Video" container="mp4,mov">
diff --git a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
index 12eba1e35..ebc5e8366 100644
--- a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
+++ b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
@@ -22,8 +22,8 @@
<MaxAlbumArtHeight>480</MaxAlbumArtHeight>
<MaxIconWidth>48</MaxIconWidth>
<MaxIconHeight>48</MaxIconHeight>
- <MaxStreamingBitrate>15000000</MaxStreamingBitrate>
- <MaxStaticBitrate>15000000</MaxStaticBitrate>
+ <MaxStreamingBitrate>20000000</MaxStreamingBitrate>
+ <MaxStaticBitrate>20000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MusicSyncBitrate>192000</MusicSyncBitrate>
<XDlnaDoc>DMS-1.50</XDlnaDoc>
@@ -43,9 +43,9 @@
<DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" />
</DirectPlayProfiles>
<TranscodingProfiles>
- <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
- <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" />
+ <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
+ <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" forceLiveStream="false" />
</TranscodingProfiles>
<ContainerProfiles />
<CodecProfiles />
diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
index a2eac41ec..1eda79f02 100644
--- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
@@ -109,30 +109,26 @@ namespace MediaBrowser.Dlna.Ssdp
var endPoint = new IPEndPoint(localIp, 1900);
- var socket = GetMulticastSocket(localIp, endPoint);
-
- var receiveBuffer = new byte[64000];
-
- CreateNotifier(localIp);
-
- while (!_tokenSource.IsCancellationRequested)
+ using (var socket = GetMulticastSocket(localIp, endPoint))
{
- var receivedBytes = await socket.ReceiveAsync(receiveBuffer, 0, 64000);
+ var receiveBuffer = new byte[64000];
- if (receivedBytes > 0)
+ CreateNotifier(localIp);
+
+ while (!_tokenSource.IsCancellationRequested)
{
- var args = SsdpHelper.ParseSsdpResponse(receiveBuffer);
- args.EndPoint = endPoint;
- args.LocalEndPoint = new IPEndPoint(localIp, 0);
+ var receivedBytes = await socket.ReceiveAsync(receiveBuffer, 0, 64000);
- if (_ssdpHandler.IgnoreMessage(args, true))
+ if (receivedBytes > 0)
{
- return;
- }
+ var args = SsdpHelper.ParseSsdpResponse(receiveBuffer);
+ args.EndPoint = endPoint;
+ args.LocalEndPoint = new IPEndPoint(localIp, 0);
- _ssdpHandler.LogMessageReceived(args, true);
+ _ssdpHandler.LogMessageReceived(args, true);
- TryCreateDevice(args);
+ TryCreateDevice(args);
+ }
}
}
diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
index 3cdeb1afd..0e791eb98 100644
--- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
@@ -479,7 +479,7 @@ namespace MediaBrowser.Dlna.Ssdp
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
- SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, 1);
+ SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, 2);
//SendUnicastRequest(msg, 1);
}
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
index 4fc1d210d..4b64295ea 100644
--- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
@@ -8,7 +8,7 @@ using CommonIO;
namespace MediaBrowser.LocalMetadata
{
- public abstract class BaseXmlProvider<T> : ILocalMetadataProvider<T>, IHasChangeMonitor, IHasOrder
+ public abstract class BaseXmlProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor, IHasOrder
where T : IHasMetadata, new()
{
protected IFileSystem FileSystem;
@@ -56,7 +56,7 @@ namespace MediaBrowser.LocalMetadata
protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var file = GetXmlFile(new ItemInfo(item), directoryService);
@@ -65,7 +65,7 @@ namespace MediaBrowser.LocalMetadata
return false;
}
- return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > date;
+ return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved;
}
public string Name
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index 968d703be..2d5225344 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -41,19 +41,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- const string vn = " -vn";
-
var threads = GetNumberOfThreads(state, false);
var inputModifier = GetInputModifier(state);
- return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
+ var albumCoverInput = string.Empty;
+ var mapArgs = string.Empty;
+ var metadata = string.Empty;
+ var vn = string.Empty;
+
+ if (!string.IsNullOrWhiteSpace(state.AlbumCoverPath))
+ {
+ albumCoverInput = " -i \"" + state.AlbumCoverPath + "\"";
+ mapArgs = " -map 0:a -map 1:v -c:v copy";
+ metadata = " -metadata:s:v title=\"Album cover\" -metadata:s:v comment=\"Cover(Front)\"";
+ }
+ else
+ {
+ vn = " -vn";
+ }
+
+ return string.Format("{0} {1}{6}{7} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{8} -y \"{5}\"",
inputModifier,
GetInputArgument(state),
threads,
vn,
string.Join(" ", audioTranscodeParams.ToArray()),
- state.OutputFilePath).Trim();
+ state.OutputFilePath,
+ albumCoverInput,
+ mapArgs,
+ metadata).Trim();
}
protected override string GetOutputFileExtension(EncodingJob state)
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 263efbb62..0ea48fab6 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -366,9 +366,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>System.String.</returns>
protected string GetVideoDecoder(EncodingJob state)
{
- if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ return null;
+ }
+
+ if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ {
+ if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
switch (state.MediaSource.VideoStream.Codec.ToLower())
{
@@ -376,7 +381,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
case "h264":
if (MediaEncoder.SupportsDecoder("h264_qsv"))
{
- return "-c:v h264_qsv ";
+ // Seeing stalls and failures with decoding. Not worth it compared to encoding.
+ //return "-c:v h264_qsv ";
}
break;
case "mpeg2video":
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index b23bd16f3..490a51128 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -64,6 +64,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public long? InputFileSize { get; set; }
public string OutputAudioSync = "1";
public string OutputVideoSync = "vfr";
+ public string AlbumCoverPath { get; set; }
public string GetMimeType(string outputPath)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 070aae3a7..1544a78b6 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -60,6 +60,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
+ var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
+ item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
+
+ if (primaryImage != null)
+ {
+ state.AlbumCoverPath = primaryImage.Path;
+ }
+
var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
@@ -575,6 +583,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
+ if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase))
+ {
+ if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value)
+ {
+ return false;
+ }
+ }
+
// If client is requesting a specific video profile, it must match the source
if (!string.IsNullOrEmpty(request.Profile))
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 01fb31d0c..399fdead9 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -96,15 +96,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
FFMpegPath = ffMpegPath;
}
+ private List<string> _encoders = new List<string>();
public void SetAvailableEncoders(List<string> list)
{
-
+ _encoders = list.ToList();
+ //_logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray()));
}
private List<string> _decoders = new List<string>();
public void SetAvailableDecoders(List<string> list)
{
_decoders = list.ToList();
+ //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));
+ }
+
+ public bool SupportsEncoder(string decoder)
+ {
+ return _encoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
}
public bool SupportsDecoder(string decoder)
@@ -112,6 +120,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
}
+ public bool CanEncodeToAudioCodec(string codec)
+ {
+ if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))
+ {
+ codec = "libopus";
+ }
+ else if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
+ {
+ codec = "libmp3lame";
+ }
+
+ return SupportsEncoder(codec);
+ }
+
/// <summary>
/// Gets the encoder path.
/// </summary>
@@ -296,7 +318,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
formats.Contains("ts", StringComparer.OrdinalIgnoreCase) ||
formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) ||
formats.Contains("wtv", StringComparer.OrdinalIgnoreCase);
-
+
// If it's mpeg based, assume true
if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1)
{
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 38528d845..c7c001cee 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -411,6 +411,17 @@ namespace MediaBrowser.MediaEncoding.Probing
NalLengthSize = streamInfo.nal_length_size
};
+ if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(streamInfo.is_avc, "1", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.IsAVC = true;
+ }
+ else if (string.Equals(streamInfo.is_avc, "false", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(streamInfo.is_avc, "0", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.IsAVC = false;
+ }
+
// Filter out junk
if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1)
{
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 54fdc6400..ba4d1b59e 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -662,9 +662,6 @@
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Games\GameSystem.cs">
- <Link>Games\GameSystem.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Globalization\CountryInfo.cs">
<Link>Globalization\CountryInfo.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 473186a46..f5d538cc4 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -636,9 +636,6 @@
<Compile Include="..\MediaBrowser.Model\FileOrganization\TvFileOrganizationOptions.cs">
<Link>FileOrganization\TvFileOrganizationOptions.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Games\GameSystem.cs">
- <Link>Games\GameSystem.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Globalization\CountryInfo.cs">
<Link>Globalization\CountryInfo.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index ba3362332..b115440d6 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -201,6 +201,7 @@ namespace MediaBrowser.Model.Configuration
public string[] Migrations { get; set; }
public int MigrationVersion { get; set; }
+ public int SchemaVersion { get; set; }
public bool DownloadImagesInAdvance { get; set; }
diff --git a/MediaBrowser.Model/Connect/ConnectUser.cs b/MediaBrowser.Model/Connect/ConnectUser.cs
index 383261a6b..da290da12 100644
--- a/MediaBrowser.Model/Connect/ConnectUser.cs
+++ b/MediaBrowser.Model/Connect/ConnectUser.cs
@@ -8,6 +8,5 @@ namespace MediaBrowser.Model.Connect
public string Email { get; set; }
public bool IsActive { get; set; }
public string ImageUrl { get; set; }
- public bool IsSupporter { get; set; }
}
}
diff --git a/MediaBrowser.Model/Dlna/ILocalPlayer.cs b/MediaBrowser.Model/Dlna/ILocalPlayer.cs
index 55e11ec4b..9de360023 100644
--- a/MediaBrowser.Model/Dlna/ILocalPlayer.cs
+++ b/MediaBrowser.Model/Dlna/ILocalPlayer.cs
@@ -23,4 +23,17 @@ namespace MediaBrowser.Model.Dlna
/// <returns><c>true</c> if this instance [can access URL] the specified URL; otherwise, <c>false</c>.</returns>
bool CanAccessUrl(string url, bool requiresCustomRequestHeaders);
}
+
+ public interface ITranscoderSupport
+ {
+ bool CanEncodeToAudioCodec(string codec);
+ }
+
+ public class FullTranscoderSupport : ITranscoderSupport
+ {
+ public bool CanEncodeToAudioCodec(string codec)
+ {
+ return true;
+ }
+ }
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 1e6b7c729..7721bfd15 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -13,15 +13,27 @@ namespace MediaBrowser.Model.Dlna
{
private readonly ILocalPlayer _localPlayer;
private readonly ILogger _logger;
+ private readonly ITranscoderSupport _transcoderSupport;
- public StreamBuilder(ILocalPlayer localPlayer, ILogger logger)
+ public StreamBuilder(ILocalPlayer localPlayer, ITranscoderSupport transcoderSupport, ILogger logger)
{
+ _transcoderSupport = transcoderSupport;
_localPlayer = localPlayer;
_logger = logger;
}
+ public StreamBuilder(ITranscoderSupport transcoderSupport, ILogger logger)
+ : this(new NullLocalPlayer(), transcoderSupport, logger)
+ {
+ }
+
+ public StreamBuilder(ILocalPlayer localPlayer, ILogger logger)
+ : this(localPlayer, new FullTranscoderSupport(), logger)
+ {
+ }
+
public StreamBuilder(ILogger logger)
- : this(new NullLocalPlayer(), logger)
+ : this(new NullLocalPlayer(), new FullTranscoderSupport(), logger)
{
}
@@ -185,8 +197,11 @@ namespace MediaBrowser.Model.Dlna
{
if (i.Type == playlistItem.MediaType && i.Context == options.Context)
{
- transcodingProfile = i;
- break;
+ if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container))
+ {
+ transcodingProfile = i;
+ break;
+ }
}
}
@@ -444,6 +459,15 @@ namespace MediaBrowser.Model.Dlna
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps;
playlistItem.ForceLiveStream = transcodingProfile.ForceLiveStream;
+
+ if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
+ {
+ int transcodingMaxAudioChannels;
+ if (IntHelper.TryParseCultureInvariant(transcodingProfile.MaxAudioChannels, out transcodingMaxAudioChannels))
+ {
+ playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels;
+ }
+ }
playlistItem.SubProtocol = transcodingProfile.Protocol;
playlistItem.AudioStreamIndex = audioStreamIndex;
@@ -1038,6 +1062,18 @@ namespace MediaBrowser.Model.Dlna
}
}
+ // Check audio codec
+ List<string> audioCodecs = profile.GetAudioCodecs();
+ if (audioCodecs.Count > 0)
+ {
+ // Check audio codecs
+ string audioCodec = audioStream == null ? null : audioStream.Codec;
+ if (string.IsNullOrEmpty(audioCodec) || !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
+ {
+ return false;
+ }
+ }
+
return true;
}
@@ -1073,6 +1109,7 @@ namespace MediaBrowser.Model.Dlna
}
}
+ // Check audio codec
List<string> audioCodecs = profile.GetAudioCodecs();
if (audioCodecs.Count > 0)
{
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 644f732a7..313c30e2c 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -38,6 +38,7 @@ namespace MediaBrowser.Model.Dlna
public int? SubtitleStreamIndex { get; set; }
+ public int? TranscodingMaxAudioChannels { get; set; }
public int? MaxAudioChannels { get; set; }
public int? AudioBitrate { get; set; }
@@ -237,7 +238,9 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString().ToLower()));
list.Add(new NameValuePair("ForceLiveStream", item.ForceLiveStream.ToString().ToLower()));
list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty));
-
+
+ list.Add(new NameValuePair("TranscodingMaxAudioChannels", item.TranscodingMaxAudioChannels.HasValue ? StringHelper.ToStringCultureInvariant(item.TranscodingMaxAudioChannels.Value) : string.Empty));
+
return list;
}
diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
index 36c357926..d1314c17b 100644
--- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
@@ -38,6 +38,9 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("forceLiveStream")]
public bool ForceLiveStream { get; set; }
+ [XmlAttribute("maxAudioChannels")]
+ public string MaxAudioChannels { get; set; }
+
public List<string> GetAudioCodecs()
{
List<string> list = new List<string>();
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 49ec9f8ef..146fcc74e 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -297,7 +297,8 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The number.</value>
public string Number { get; set; }
-
+ public string ChannelNumber { get; set; }
+
/// <summary>
/// Gets or sets the index number.
/// </summary>
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index fa7a51291..25252956b 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -42,6 +42,8 @@ namespace MediaBrowser.Model.Entities
/// <value><c>true</c> if this instance is interlaced; otherwise, <c>false</c>.</value>
public bool IsInterlaced { get; set; }
+ public bool? IsAVC { get; set; }
+
/// <summary>
/// Gets or sets the channel layout.
/// </summary>
diff --git a/MediaBrowser.Model/Games/GameSystem.cs b/MediaBrowser.Model/Games/GameSystem.cs
deleted file mode 100644
index ab8f1efa7..000000000
--- a/MediaBrowser.Model/Games/GameSystem.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-
-namespace MediaBrowser.Model.Games
-{
- public class GameSystem
- {
- public const string Nintendo = "Nintendo";
- public const string SuperNintendo = "Super Nintendo";
- public const string Panasonic3DO = "3DO";
- public const string Amiga = "Amiga";
- public const string Arcade = "Arcade";
- public const string Atari2600 = "Atari 2600";
- public const string Atari5200 = "Atari 5200";
- public const string Atari7800 = "Atari 7800";
- public const string AtariXE = "Atari XE";
- public const string AtariJaguar = "Atari Jaguar";
- public const string AtariJaguarCD = "Atari Jaguar CD";
- public const string Colecovision = "Colecovision";
- public const string Commodore64 = "Commodore 64";
- public const string CommodoreVic20 = "Commodore Vic-20";
- public const string Intellivision = "Intellivision";
- public const string MicrosoftXBox = "Xbox";
- public const string NeoGeo = "Neo Geo";
- public const string Nintendo64 = "Nintendo 64";
- public const string NintendoDS = "Nintendo DS";
- public const string NintendoGameBoy = "Game Boy";
- public const string NintendoGameBoyAdvance = "Game Boy Advance";
- public const string NintendoGameBoyColor = "Game Boy Color";
- public const string NintendoGameCube = "Gamecube";
- public const string VirtualBoy = "Virtual Boy";
- public const string Wii = "Nintendo Wii";
- public const string DOS = "DOS";
- public const string Windows = "Windows";
- public const string Sega32X = "Sega 32X";
- public const string SegaCD = "Sega CD";
- public const string SegaDreamcast = "Dreamcast";
- public const string SegaGameGear = "Game Gear";
- public const string SegaGenesis = "Sega Genesis";
- public const string SegaMasterSystem = "Sega Master System";
- public const string SegaMegaDrive = "Sega Mega Drive";
- public const string SegaSaturn = "Sega Saturn";
- public const string SonyPlaystation = "Sony Playstation";
- public const string SonyPlaystation2 = "PS2";
- public const string SonyPSP = "PSP";
- public const string TurboGrafx16 = "TurboGrafx 16";
- public const string TurboGrafxCD = "TurboGrafx CD";
- public const string ZxSpectrum = "ZX Spectrum";
- }
-}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 46f630fe0..4211fbd59 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -7,8 +7,12 @@ namespace MediaBrowser.Model.LiveTv
public int? GuideDays { get; set; }
public bool EnableMovieProviders { get; set; }
public string RecordingPath { get; set; }
+ public string MovieRecordingPath { get; set; }
+ public string SeriesRecordingPath { get; set; }
public bool EnableAutoOrganize { get; set; }
public bool EnableRecordingEncoding { get; set; }
+ public bool EnableRecordingSubfolders { get; set; }
+ public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
public List<TunerHostInfo> TunerHosts { get; set; }
public List<ListingsProviderInfo> ListingProviders { get; set; }
@@ -19,6 +23,7 @@ namespace MediaBrowser.Model.LiveTv
public LiveTvOptions()
{
EnableMovieProviders = true;
+ EnableRecordingSubfolders = true;
TunerHosts = new List<TunerHostInfo>();
ListingProviders = new List<ListingsProviderInfo>();
}
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index 7a877e356..0141191c1 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -14,8 +14,11 @@ namespace MediaBrowser.Model.LiveTv
ChannelIds = new string[] { };
SortBy = new string[] { };
Genres = new string[] { };
+ EnableTotalRecordCount = true;
}
+ public bool EnableTotalRecordCount { get; set; }
+
/// <summary>
/// Fields to return within the items, in addition to basic information
/// </summary>
diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
index e83a8fda6..0e6d081a1 100644
--- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
@@ -13,7 +13,14 @@ 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 RecommendedProgramQuery()
+ {
+ EnableTotalRecordCount = true;
+ }
+
/// <summary>
/// Gets or sets the user identifier.
/// </summary>
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 41952963c..7c469b9fb 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -287,7 +287,6 @@
<Compile Include="Entities\MetadataFields.cs" />
<Compile Include="Entities\UserDataSaveReason.cs" />
<Compile Include="Entities\Video3DFormat.cs" />
- <Compile Include="Games\GameSystem.cs" />
<Compile Include="IO\IIsoManager.cs" />
<Compile Include="IO\IIsoMount.cs" />
<Compile Include="IO\IIsoMounter.cs" />
diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs
index 77464be58..1c72ccd52 100644
--- a/MediaBrowser.Model/Sync/SyncJobItem.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItem.cs
@@ -102,6 +102,8 @@ namespace MediaBrowser.Model.Sync
/// <value>The index of the job item.</value>
public int JobItemIndex { get; set; }
+ public long ItemDateModifiedTicks { get; set; }
+
public SyncJobItem()
{
AdditionalFiles = new List<ItemFileInfo>();
diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
index ff3d5a5b2..b3e73740d 100644
--- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
+++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
@@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.BoxSets
{
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
return GetImages(mainResult, language, tmdbImageUrl);
}
diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
index 53a573bd1..ab05c959e 100644
--- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
+++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.BoxSets
{
public class MovieDbBoxSetProvider : IRemoteMetadataProvider<BoxSet, BoxSetInfo>
{
- private const string GetCollectionInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
+ private const string GetCollectionInfo3 = @"https://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
internal static MovieDbBoxSetProvider Current;
@@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.BoxSets
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
var result = new RemoteSearchResult
{
@@ -190,7 +190,7 @@ namespace MediaBrowser.Providers.BoxSets
cancellationToken.ThrowIfCancellationRequested();
- if (mainResult != null && string.IsNullOrEmpty(mainResult.overview))
+ if (mainResult != null && string.IsNullOrEmpty(mainResult.name))
{
if (!string.IsNullOrEmpty(language) && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
index afd8c583d..08b4f6461 100644
--- a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
+++ b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
@@ -117,7 +117,7 @@ namespace MediaBrowser.Providers.Folders
}
if (string.IsNullOrWhiteSpace(viewType))
{
- return urlPrefix + "generic.jpg";
+ //return urlPrefix + "generic.jpg";
}
return null;
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index eeec4ea56..a0c6bd889 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -295,22 +295,22 @@ namespace MediaBrowser.Providers.Manager
return true;
}
- if (item is BoxSet || item is IItemByName || item is Playlist)
+ if (!(item is Audio) && !(item is Video))
{
return true;
}
- if (item.SourceType != SourceType.Library)
+ if (item is IItemByName)
{
return true;
}
- if (item is ICollectionFolder)
+ if (item.SourceType != SourceType.Library)
{
return true;
}
- if (!(item is Audio) && !(item is Video))
+ if (item is MusicVideo)
{
return true;
}
@@ -395,7 +395,6 @@ namespace MediaBrowser.Providers.Manager
return _cachedTask;
}
- private readonly Task<ItemUpdateType> _cachedResult = Task.FromResult(ItemUpdateType.None);
/// <summary>
/// Befores the save.
/// </summary>
@@ -403,9 +402,60 @@ namespace MediaBrowser.Providers.Manager
/// <param name="isFullRefresh">if set to <c>true</c> [is full refresh].</param>
/// <param name="currentUpdateType">Type of the current update.</param>
/// <returns>ItemUpdateType.</returns>
- protected virtual Task<ItemUpdateType> BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType)
+ protected virtual async Task<ItemUpdateType> BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType)
+ {
+ var updateType = ItemUpdateType.None;
+
+ updateType |= SaveCumulativeRunTimeTicks(item, isFullRefresh, currentUpdateType);
+ updateType |= SaveDateLastMediaAdded(item, isFullRefresh, currentUpdateType);
+
+ return updateType;
+ }
+
+ private ItemUpdateType SaveCumulativeRunTimeTicks(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType)
+ {
+ var updateType = ItemUpdateType.None;
+
+ if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
+ {
+ var folder = item as Folder;
+ if (folder != null && folder.SupportsCumulativeRunTimeTicks)
+ {
+ var items = folder.GetRecursiveChildren(i => !i.IsFolder).ToList();
+ var ticks = items.Select(i => i.RunTimeTicks ?? 0).Sum();
+
+ if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks)
+ {
+ folder.RunTimeTicks = ticks;
+ updateType = ItemUpdateType.MetadataEdit;
+ }
+ }
+ }
+
+ return updateType;
+ }
+
+ private ItemUpdateType SaveDateLastMediaAdded(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType)
{
- return _cachedResult;
+ var updateType = ItemUpdateType.None;
+
+ if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
+ {
+ var folder = item as Folder;
+ if (folder != null && folder.SupportsDateLastMediaAdded)
+ {
+ var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList();
+ var date = items.Count == 0 ? (DateTime?)null : items.Max();
+
+ if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date)
+ {
+ folder.DateLastMediaAdded = date;
+ updateType = ItemUpdateType.MetadataEdit;
+ }
+ }
+ }
+
+ return updateType;
}
/// <summary>
@@ -425,7 +475,7 @@ namespace MediaBrowser.Providers.Manager
: status.DateLastMetadataRefresh ?? default(DateTime);
// Run all if either of these flags are true
- var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime);
+ var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || item.RequiresRefresh();
if (!runAllProviders)
{
@@ -435,18 +485,18 @@ namespace MediaBrowser.Providers.Manager
var providersWithChanges = providers
.Where(i =>
{
- var hasChangeMonitor = i as IHasChangeMonitor;
- if (hasChangeMonitor != null)
- {
- return HasChanged(item, hasChangeMonitor, currentItem.DateLastSaved, options.DirectoryService);
- }
-
var hasFileChangeMonitor = i as IHasItemChangeMonitor;
if (hasFileChangeMonitor != null)
{
return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
}
+ var hasChangeMonitor = i as IHasChangeMonitor;
+ if (hasChangeMonitor != null)
+ {
+ return HasChanged(item, hasChangeMonitor, currentItem.DateLastSaved, options.DirectoryService);
+ }
+
return false;
})
.ToList();
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 3199ed12b..c95d58a42 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Manager
{
@@ -60,6 +61,7 @@ namespace MediaBrowser.Providers.Manager
private IEnumerable<IMetadataSaver> _savers;
private IImageSaver[] _imageSavers;
private readonly IServerApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
private IExternalId[] _externalIds;
@@ -73,7 +75,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="libraryMonitor">The directory watchers.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="fileSystem">The file system.</param>
- public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory)
+ public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory, IJsonSerializer json)
{
_logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient;
@@ -82,6 +84,7 @@ namespace MediaBrowser.Providers.Manager
_fileSystem = fileSystem;
_appPaths = appPaths;
_libraryManagerFactory = libraryManagerFactory;
+ _json = json;
}
/// <summary>
@@ -730,8 +733,6 @@ namespace MediaBrowser.Providers.Manager
where TItemType : BaseItem, new()
where TLookupType : ItemLookupInfo
{
- const int maxResults = 10;
-
// Give it a dummy path just so that it looks like a file system item
var dummy = new TItemType
{
@@ -761,7 +762,6 @@ namespace MediaBrowser.Providers.Manager
}
var resultList = new List<RemoteSearchResult>();
- var foundProviderIds = new Dictionary<Tuple<string, string>, RemoteSearchResult>();
foreach (var provider in providers)
{
@@ -771,31 +771,26 @@ namespace MediaBrowser.Providers.Manager
foreach (var result in results)
{
- var bFound = false;
+ var existingMatch = resultList.FirstOrDefault(i => i.ProviderIds.Any(p => string.Equals(result.GetProviderId(p.Key), p.Value, StringComparison.OrdinalIgnoreCase)));
- // This check prevents duplicate search results by comparing provider ids
- foreach (var providerId in result.ProviderIds)
+ if (existingMatch == null)
{
- var idTuple = new Tuple<string, string>(providerId.Key.ToLower(), providerId.Value.ToLower());
-
- if (!foundProviderIds.ContainsKey(idTuple))
- {
- foundProviderIds.Add(idTuple, result);
- }
- else
+ resultList.Add(result);
+ }
+ else
+ {
+ foreach (var providerId in result.ProviderIds)
{
- bFound = true;
- var existingResult = foundProviderIds[idTuple];
- if (string.IsNullOrEmpty(existingResult.ImageUrl) && !string.IsNullOrEmpty(result.ImageUrl))
+ if (!existingMatch.ProviderIds.ContainsKey(providerId.Key))
{
- existingResult.ImageUrl = result.ImageUrl;
+ existingMatch.ProviderIds.Add(providerId.Key, providerId.Value);
}
}
- }
- if (!bFound && resultList.Count < maxResults)
- {
- resultList.Add(result);
+ if (string.IsNullOrWhiteSpace(existingMatch.ImageUrl))
+ {
+ existingMatch.ImageUrl = result.ImageUrl;
+ }
}
}
}
@@ -805,6 +800,8 @@ namespace MediaBrowser.Providers.Manager
}
}
+ //_logger.Debug("Returning search results {0}", _json.SerializeToString(resultList));
+
return resultList;
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index 9db4ab96e..b89b0b925 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -30,6 +30,7 @@ namespace MediaBrowser.Providers.MediaInfo
ICustomMetadataProvider<Movie>,
ICustomMetadataProvider<LiveTvVideoRecording>,
ICustomMetadataProvider<LiveTvAudioRecording>,
+ ICustomMetadataProvider<Trailer>,
ICustomMetadataProvider<Video>,
ICustomMetadataProvider<Audio>,
IHasItemChangeMonitor,
@@ -77,6 +78,11 @@ namespace MediaBrowser.Providers.MediaInfo
return FetchVideoInfo(item, options, cancellationToken);
}
+ public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchVideoInfo(item, options, cancellationToken);
+ }
+
public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
return FetchVideoInfo(item, options, cancellationToken);
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 621510028..e1ab61cbb 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -444,7 +444,11 @@ namespace MediaBrowser.Providers.MediaInfo
{
if (string.IsNullOrWhiteSpace(video.Name) || string.Equals(video.Name, Path.GetFileNameWithoutExtension(video.Path), StringComparison.OrdinalIgnoreCase))
{
- video.Name = data.Name;
+ // Don't use the embedded name for extras because it will often be the same name as the movie
+ if (!video.ExtraType.HasValue && !video.IsOwnedItem)
+ {
+ video.Name = data.Name;
+ }
}
}
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
index d207e6e7c..5262f8e3b 100644
--- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Movies
{
class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask
{
- private const string UpdatesUrl = "http://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
+ private const string UpdatesUrl = "https://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
/// <summary>
/// The _HTTP client
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index a1dbc1967..775e6dfb9 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -16,6 +16,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
@@ -23,7 +24,7 @@ using MediaBrowser.Providers.TV;
namespace MediaBrowser.Providers.Movies
{
- public class FanartMovieImageProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
+ public class FanartMovieImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -31,7 +32,7 @@ namespace MediaBrowser.Providers.Movies
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _json;
- private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/movies/{1}?api_key={0}";
+ private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3/movies/{1}?api_key={0}";
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
internal static FanartMovieImageProvider Current;
@@ -185,6 +186,7 @@ namespace MediaBrowser.Providers.Movies
PopulateImages(list, obj.moviebackground, ImageType.Backdrop, 1920, 1080);
}
+ private Regex _regex_http = new Regex("^http://");
private void PopulateImages(List<RemoteImageInfo> list, List<Image> images, ImageType type, int width, int height)
{
if (images == null)
@@ -208,7 +210,7 @@ namespace MediaBrowser.Providers.Movies
Width = width,
Height = height,
ProviderName = Name,
- Url = url,
+ Url = _regex_http.Replace(url, "https://", 1),
Language = i.lang
};
@@ -239,7 +241,7 @@ namespace MediaBrowser.Providers.Movies
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var options = FanartSeriesProvider.Current.GetFanartOptions();
if (!options.EnableAutomaticUpdates)
@@ -260,7 +262,7 @@ namespace MediaBrowser.Providers.Movies
var fileInfo = _fileSystem.GetFileInfo(path);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index 6c6f6f0eb..d13716cba 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -249,7 +249,7 @@ namespace MediaBrowser.Providers.Movies
}
resultItem.ResetPeople();
- var tmdbImageUrl = settings.images.base_url + "original";
+ var tmdbImageUrl = settings.images.secure_base_url + "original";
//Actors, Directors, Writers - all in People
//actors come from cast
@@ -329,7 +329,7 @@ namespace MediaBrowser.Providers.Movies
{
hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
{
- Url = string.Format("http://www.youtube.com/watch?v={0}", i.source),
+ 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
diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
index e091cddc6..5958c3a0a 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
@@ -17,7 +17,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.Movies
{
- class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
+ class MovieDbImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
@@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Movies
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
var supportedImages = GetSupportedImages(item).ToList();
@@ -222,9 +222,9 @@ namespace MediaBrowser.Providers.Movies
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- return MovieDbProvider.Current.HasChanged(item, date);
+ return MovieDbProvider.Current.HasChanged(item);
}
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index 51051e41d..c588a9a69 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -78,7 +78,7 @@ namespace MediaBrowser.Providers.Movies
var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
var remoteResult = new RemoteSearchResult
{
@@ -172,8 +172,8 @@ namespace MediaBrowser.Providers.Movies
}
}
- private const string TmdbConfigUrl = "http://api.themoviedb.org/3/configuration?api_key={0}";
- private const string GetMovieInfo3 = @"http://api.themoviedb.org/3/movie/{0}?api_key={1}&append_to_response=casts,releases,images,keywords,trailers";
+ private const string TmdbConfigUrl = "https://api.themoviedb.org/3/configuration?api_key={0}";
+ private const string GetMovieInfo3 = @"https://api.themoviedb.org/3/movie/{0}?api_key={1}&append_to_response=casts,releases,images,keywords,trailers";
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
internal static string AcceptHeader = "application/json,image/*";
@@ -281,7 +281,7 @@ namespace MediaBrowser.Providers.Movies
public static string NormalizeLanguage(string language)
{
// They require this to be uppercase
- // http://emby.media/community/index.php?/topic/32454-fr-follow-tmdbs-new-language-api-update/?p=311148
+ // https://emby.media/community/index.php?/topic/32454-fr-follow-tmdbs-new-language-api-update/?p=311148
var parts = language.Split('-');
if (parts.Length == 2)
@@ -414,7 +414,7 @@ namespace MediaBrowser.Providers.Movies
return _configurationManager.GetConfiguration<TheMovieDbOptions>("themoviedb");
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item)
{
if (!GetTheMovieDbOptions().EnableAutomaticUpdates)
{
@@ -430,7 +430,7 @@ namespace MediaBrowser.Providers.Movies
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
index e8eeab9c5..ceb41178e 100644
--- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Movies
public class MovieDbSearch
{
private static readonly CultureInfo EnUs = new CultureInfo("en-US");
- private const string Search3 = @"http://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}";
+ private const string Search3 = @"https://api.themoviedb.org/3/search/{3}?api_key={1}&query={0}&language={2}";
internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
internal static string AcceptHeader = "application/json,image/*";
@@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.Movies
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
if (!string.IsNullOrWhiteSpace(name))
{
diff --git a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
index 336968a84..5fb3ea369 100644
--- a/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
@@ -33,9 +33,9 @@ namespace MediaBrowser.Providers.Movies
get { return MovieDbProvider.Current.Name; }
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- return MovieDbProvider.Current.HasChanged(item, date);
+ return MovieDbProvider.Current.HasChanged(item);
}
public int Order
diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs
index 02c330267..3bceb976e 100644
--- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs
+++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Movies
public string UrlFormatString
{
- get { return "http://www.themoviedb.org/movie/{0}"; }
+ get { return "https://www.themoviedb.org/movie/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -51,7 +51,7 @@ namespace MediaBrowser.Providers.Movies
public string UrlFormatString
{
- get { return "http://www.themoviedb.org/tv/{0}"; }
+ get { return "https://www.themoviedb.org/tv/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.Movies
public string UrlFormatString
{
- get { return "http://www.themoviedb.org/collection/{0}"; }
+ get { return "https://www.themoviedb.org/collection/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.Movies
public string UrlFormatString
{
- get { return "http://www.themoviedb.org/person/{0}"; }
+ get { return "https://www.themoviedb.org/person/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -120,7 +120,7 @@ namespace MediaBrowser.Providers.Movies
public string UrlFormatString
{
- get { return "http://www.themoviedb.org/collection/{0}"; }
+ get { return "https://www.themoviedb.org/collection/{0}"; }
}
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
index 7fa7e0d15..70c155ad5 100644
--- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
+++ b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
/// <summary>
/// The updates URL
/// </summary>
- private const string UpdatesUrl = "http://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}";
+ private const string UpdatesUrl = "https://api.themoviedb.org/3/movie/changes?start_date={0}&api_key={1}&page={2}";
/// <summary>
/// The _HTTP client
@@ -176,9 +176,13 @@ namespace MediaBrowser.Providers.Movies
var numComplete = 0;
// Gather all movies into a lookup by tmdb id
- var allMovies = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is Movie && !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb)))
- .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb));
+ var allMovies = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
+ {
+ IncludeItemTypes = new[] {typeof (Movie).Name},
+ Recursive = true
+
+ }).Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb)))
+ .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb));
foreach (var id in list)
{
diff --git a/MediaBrowser.Providers/Movies/TmdbSettings.cs b/MediaBrowser.Providers/Movies/TmdbSettings.cs
index 59e8f7cef..12bb77afc 100644
--- a/MediaBrowser.Providers/Movies/TmdbSettings.cs
+++ b/MediaBrowser.Providers/Movies/TmdbSettings.cs
@@ -5,7 +5,7 @@ namespace MediaBrowser.Providers.Movies
internal class TmdbImageSettings
{
public List<string> backdrop_sizes { get; set; }
- public string base_url { get; set; }
+ public string secure_base_url { get; set; }
public List<string> poster_sizes { get; set; }
public List<string> profile_sizes { get; set; }
}
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 0c0339e12..21e9b006b 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -27,10 +27,12 @@ namespace MediaBrowser.Providers.Music
{
if (!item.IsLocked)
{
- var itemFilter = item.GetItemFilter();
-
var taggedItems = item.IsAccessedByName ?
- LibraryManager.RootFolder.GetRecursiveChildren(i => !i.IsFolder && itemFilter(i)).ToList() :
+ item.GetTaggedItems(new Controller.Entities.InternalItemsQuery()
+ {
+ Recursive = true,
+ IsFolder = false
+ }) :
item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder).ToList();
if (!item.LockedFields.Contains(MetadataFields.Genres))
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index 444046208..5b3bd87db 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -19,7 +19,7 @@ using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Music
{
- public class FanartAlbumProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
+ public class FanartAlbumProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -213,7 +213,7 @@ namespace MediaBrowser.Providers.Music
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var options = FanartSeriesProvider.Current.GetFanartOptions();
if (!options.EnableAutomaticUpdates)
@@ -235,7 +235,7 @@ namespace MediaBrowser.Providers.Music
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
}
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index b715803ea..37b51da5a 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -22,11 +22,11 @@ using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Providers.Music
{
- public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
+ public class FanartArtistProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
{
internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
- private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3.1/music/{1}?api_key={0}";
+ private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3.1/music/{1}?api_key={0}";
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -207,7 +207,7 @@ namespace MediaBrowser.Providers.Music
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var options = FanartSeriesProvider.Current.GetFanartOptions();
if (!options.EnableAutomaticUpdates)
@@ -224,7 +224,7 @@ namespace MediaBrowser.Providers.Music
var fileInfo = _fileSystem.GetFileInfo(artistJsonPath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
index 30507b891..3b829af9e 100644
--- a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Music
{
class FanartUpdatesPostScanTask : ILibraryPostScanTask
{
- private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmusic/{0}/{1}/";
+ private const string UpdatesUrl = "https://api.fanart.tv/webservice/newmusic/{0}/{1}/";
/// <summary>
/// The _HTTP client
diff --git a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
index 55dcc99f5..d031b3d6b 100644
--- a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
+++ b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs
@@ -27,9 +27,9 @@ namespace MediaBrowser.Providers.Music
get { return MovieDbProvider.Current.Name; }
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- return MovieDbProvider.Current.HasChanged(item, date);
+ return MovieDbProvider.Current.HasChanged(item);
}
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index e73a98b6f..e41982ef6 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrEmpty(releaseId))
{
- url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
+ url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
}
else
{
@@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Music
if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
{
- url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(searchInfo.Name),
artistMusicBrainzId);
}
@@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.Music
{
isNameSearch = true;
- url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(searchInfo.Name),
WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
}
@@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.Music
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
{
var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
+ ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
var list = new List<RemoteSearchResult>();
@@ -197,7 +197,7 @@ namespace MediaBrowser.Providers.Music
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
{
- var url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
+ var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
WebUtility.UrlEncode(albumName),
artistId);
@@ -208,7 +208,7 @@ namespace MediaBrowser.Providers.Music
private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken)
{
- var url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+ var url = string.Format("https://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
WebUtility.UrlEncode(albumName),
WebUtility.UrlEncode(artistName));
@@ -220,7 +220,7 @@ namespace MediaBrowser.Providers.Music
private ReleaseResult GetReleaseResult(XmlDocument doc)
{
var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
+ ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
var result = new ReleaseResult
{
@@ -258,12 +258,12 @@ namespace MediaBrowser.Providers.Music
/// <returns>Task{System.String}.</returns>
private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
{
- var url = string.Format("http://www.musicbrainz.org/ws/2/release-group/?query=reid:{0}", releaseEntryId);
+ var url = string.Format("https://www.musicbrainz.org/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", "http://musicbrainz.org/ns/mmd-2.0#");
+ ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
return node != null ? node.Value : null;
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index c04f80549..2eb65f4e5 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("http://www.musicbrainz.org/ws/2/artist/?query=arid:{0}", musicBrainzId);
+ var url = string.Format("https://www.musicbrainz.org/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("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
+ var url = String.Format("https://www.musicbrainz.org/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("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
+ url = String.Format("https://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false);
@@ -62,12 +62,25 @@ namespace MediaBrowser.Providers.Music
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
{
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
+ //var ns = new XmlNamespaceManager(doc.NameTable);
+ //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#");
var list = new List<RemoteSearchResult>();
- var nodes = doc.SelectNodes("//mb:artist-list/mb:artist", ns);
+ var docElem = doc.DocumentElement;
+
+ if (docElem == null)
+ {
+ return list;
+ }
+
+ var artistList = docElem.FirstChild;
+ if (artistList == null)
+ {
+ return list;
+ }
+
+ var nodes = artistList.ChildNodes;
if (nodes != null)
{
@@ -79,11 +92,13 @@ namespace MediaBrowser.Providers.Music
string mbzId = node.Attributes["id"].Value;
- var nameNode = node.SelectSingleNode("//mb:name", ns);
-
- if (nameNode != null)
+ foreach (var child in node.ChildNodes.Cast<XmlNode>())
{
- name = nameNode.InnerText;
+ if (string.Equals(child.Name, "name", StringComparison.OrdinalIgnoreCase))
+ {
+ name = node.InnerText;
+ break;
+ }
}
if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name))
diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs
index bcafdc6f6..814488df1 100644
--- a/MediaBrowser.Providers/Music/MusicExternalIds.cs
+++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/release-group/{0}"; }
+ get { return "https://musicbrainz.org/release-group/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/artist/{0}"; }
+ get { return "https://musicbrainz.org/artist/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/release/{0}"; }
+ get { return "https://musicbrainz.org/release/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/artist/{0}"; }
+ get { return "https://musicbrainz.org/artist/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/artist/{0}"; }
+ get { return "https://musicbrainz.org/artist/{0}"; }
}
public bool Supports(IHasProviderIds item)
@@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.Music
public string UrlFormatString
{
- get { return "http://musicbrainz.org/track/{0}"; }
+ get { return "https://musicbrainz.org/track/{0}"; }
}
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index ae563b287..a1e038374 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -40,7 +40,7 @@ namespace MediaBrowser.Providers.Omdb
list.Add(new RemoteImageInfo
{
ProviderName = Name,
- Url = string.Format("http://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
+ Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=82e83907", imdbId)
});
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
index 1b8ecd521..a0d60c166 100644
--- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
@@ -64,11 +64,9 @@ namespace MediaBrowser.Providers.Omdb
{
var episodeSearchInfo = searchInfo as EpisodeInfo;
- var list = new List<RemoteSearchResult>();
-
var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
- var url = "http://www.omdbapi.com/?plot=full&r=json";
+ var url = "https://www.omdbapi.com/?plot=full&r=json";
if (type == "episode" && episodeSearchInfo != null)
{
episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId);
@@ -148,14 +146,13 @@ namespace MediaBrowser.Providers.Omdb
}
}
- foreach (var result in resultList)
+ return resultList.Select(result =>
{
var item = new RemoteSearchResult
{
IndexNumber = searchInfo.IndexNumber,
Name = result.Title,
ParentIndexNumber = searchInfo.ParentIndexNumber,
- ProviderIds = searchInfo.ProviderIds,
SearchProviderName = Name
};
@@ -185,11 +182,9 @@ namespace MediaBrowser.Providers.Omdb
item.ImageUrl = result.Poster;
}
- list.Add(item);
- }
+ return item;
+ });
}
-
- return list;
}
public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index b68f93cf6..44e250350 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Omdb
var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
- var url = string.Format("http://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
+ var url = string.Format("https://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
using (var stream = await _httpClient.Get(new HttpRequestOptions
{
diff --git a/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
index 2ac9fdfa0..93eee69ae 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.People
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
return GetImages(images, item.GetPreferredMetadataLanguage(), tmdbImageUrl);
}
diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
index 2b37d0462..bb17b83ec 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
@@ -59,7 +59,7 @@ namespace MediaBrowser.Providers.People
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
if (!string.IsNullOrEmpty(tmdbId))
{
@@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.People
var requestCount = _requestCount;
- if (requestCount >= 30)
+ if (requestCount >= 40)
{
//_logger.Debug("Throttling Tmdb people");
@@ -109,7 +109,7 @@ namespace MediaBrowser.Providers.People
}
}
- var url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey);
+ var url = string.Format(@"https://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey);
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
@@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.People
return;
}
- var url = string.Format(@"http://api.themoviedb.org/3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", MovieDbProvider.ApiKey, id);
+ var url = string.Format(@"https://api.themoviedb.org/3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", MovieDbProvider.ApiKey, id);
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
index 5cf9966e8..2c6e27294 100644
--- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
@@ -40,7 +40,7 @@ namespace MediaBrowser.Providers.TV
if (hasNewSeasons)
{
- var directoryService = new DirectoryService(_fileSystem);
+ //var directoryService = new DirectoryService(_fileSystem);
//await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false);
@@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.TV
// Season does not have a number
// Remove if there are no episodes directly in series without a season number
- return episodes.All(s => s.ParentIndexNumber.HasValue || !s.IsInSeasonFolder);
+ return episodes.All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
})
.ToList();
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
index e683907c4..673663d7f 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
@@ -21,7 +21,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
+ public class FanArtSeasonProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -225,7 +225,7 @@ namespace MediaBrowser.Providers.TV
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var options = FanartSeriesProvider.Current.GetFanartOptions();
if (!options.EnableAutomaticUpdates)
@@ -250,7 +250,7 @@ namespace MediaBrowser.Providers.TV
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs b/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs
index 049ffd7d8..37e76531b 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanArtTvUpdatesPostScanTask.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.TV
{
class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask
{
- private const string UpdatesUrl = "http://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
+ private const string UpdatesUrl = "https://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
/// <summary>
/// The _HTTP client
diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
index 517951cb8..3c831dbbc 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
@@ -23,7 +23,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
+ public class FanartSeriesProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
@@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.TV
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _json;
- private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/tv/{1}?api_key={0}";
+ private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3/tv/{1}?api_key={0}";
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
internal static FanartSeriesProvider Current { get; private set; }
@@ -341,7 +341,7 @@ namespace MediaBrowser.Providers.TV
}
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var options = GetFanartOptions();
if (!options.EnableAutomaticUpdates)
@@ -358,7 +358,7 @@ namespace MediaBrowser.Providers.TV
var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index ad55c186a..e79ad2dfb 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -27,6 +27,8 @@ namespace MediaBrowser.Providers.TV
private readonly IFileSystem _fileSystem;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private static readonly SemaphoreSlim _resourceLock = new SemaphoreSlim(1, 1);
+ public static bool IsRunning = false;
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, IFileSystem fileSystem)
{
@@ -37,13 +39,16 @@ namespace MediaBrowser.Providers.TV
_fileSystem = fileSystem;
}
- public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
+ public async Task Run(List<IGrouping<string, Series>> series, bool addNewItems, CancellationToken cancellationToken)
{
+ await _resourceLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ IsRunning = true;
+
foreach (var seriesGroup in series)
{
try
{
- await Run(seriesGroup, cancellationToken).ConfigureAwait(false);
+ await Run(seriesGroup, addNewItems, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -58,9 +63,12 @@ namespace MediaBrowser.Providers.TV
_logger.ErrorException("Error in missing episode provider for series id {0}", ex, seriesGroup.Key);
}
}
+
+ IsRunning = false;
+ _resourceLock.Release();
}
- private async Task Run(IGrouping<string, Series> group, CancellationToken cancellationToken)
+ private async Task Run(IGrouping<string, Series> group, bool addNewItems, CancellationToken cancellationToken)
{
var tvdbId = group.Key;
@@ -110,7 +118,7 @@ namespace MediaBrowser.Providers.TV
var hasNewEpisodes = false;
- if (_config.Configuration.EnableInternetProviders)
+ if (_config.Configuration.EnableInternetProviders && addNewItems)
{
var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
@@ -372,7 +380,7 @@ namespace MediaBrowser.Providers.TV
// Season does not have a number
// Remove if there are no episodes directly in series without a season number
- return i.Season.Series.GetRecursiveChildren().OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || !s.IsInSeasonFolder);
+ return i.Season.Series.GetRecursiveChildren().OfType<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder);
})
.ToList();
@@ -427,7 +435,7 @@ namespace MediaBrowser.Providers.TV
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
- await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
+ await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
}, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
index 1af116289..292923d82 100644
--- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using CommonIO;
@@ -31,6 +32,13 @@ namespace MediaBrowser.Providers.TV
}
}
+ if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
+ {
+ var episodes = item.GetEpisodes().ToList();
+ updateType |= SavePremiereDate(item, episodes);
+ updateType |= SaveIsMissing(item, episodes);
+ }
+
return updateType;
}
@@ -38,5 +46,38 @@ namespace MediaBrowser.Providers.TV
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
+
+ private ItemUpdateType SavePremiereDate(Season item, List<Episode> episodes)
+ {
+ var dates = episodes.Where(i => i.PremiereDate.HasValue).Select(i => i.PremiereDate.Value).ToList();
+
+ DateTime? premiereDate = null;
+
+ if (dates.Count > 0)
+ {
+ premiereDate = dates.Min();
+ }
+
+ if (item.PremiereDate != premiereDate)
+ {
+ item.PremiereDate = premiereDate;
+ return ItemUpdateType.MetadataEdit;
+ }
+
+ return ItemUpdateType.None;
+ }
+
+ private ItemUpdateType SaveIsMissing(Season item, List<Episode> episodes)
+ {
+ var isMissing = item.LocationType == LocationType.Virtual && episodes.All(i => i.IsMissingEpisode);
+
+ if (item.IsMissingSeason != isMissing)
+ {
+ item.IsMissingSeason = isMissing;
+ return ItemUpdateType.MetadataEdit;
+ }
+
+ return ItemUpdateType.None;
+ }
}
}
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index 5428e6c92..3c0a5fc73 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -11,6 +11,10 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Tasks;
namespace MediaBrowser.Providers.TV
{
@@ -46,14 +50,18 @@ namespace MediaBrowser.Providers.TV
private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
{
- var seriesList = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is Series)
- .Cast<Series>()
- .ToList();
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
+
+ }).Cast<Series>().ToList();
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
- await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
+ await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem)
+ .Run(seriesGroups, true, cancellationToken).ConfigureAwait(false);
var numComplete = 0;
@@ -82,7 +90,7 @@ namespace MediaBrowser.Providers.TV
}
}
- private IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList)
+ internal static IEnumerable<IGrouping<string, Series>> FindSeriesGroups(List<Series> seriesList)
{
var links = seriesList.ToDictionary(s => s, s => seriesList.Where(c => c != s && ShareProviderId(s, c)).ToList());
@@ -102,7 +110,7 @@ namespace MediaBrowser.Providers.TV
}
}
- private void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results)
+ private static void FindAllLinked(Series series, HashSet<Series> visited, IDictionary<Series, List<Series>> linksMap, List<Series> results)
{
results.Add(series);
visited.Add(series);
@@ -118,7 +126,7 @@ namespace MediaBrowser.Providers.TV
}
}
- private bool ShareProviderId(Series a, Series b)
+ private static bool ShareProviderId(Series a, Series b)
{
return a.ProviderIds.Any(id =>
{
@@ -137,4 +145,109 @@ namespace MediaBrowser.Providers.TV
}
}
+ public class CleanMissingEpisodesEntryPoint : IServerEntryPoint
+ {
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _config;
+ private readonly ILogger _logger;
+ private readonly ILocalizationManager _localization;
+ private readonly IFileSystem _fileSystem;
+ private readonly object _libraryChangedSyncLock = new object();
+ private const int LibraryUpdateDuration = 180000;
+ private readonly ITaskManager _taskManager;
+
+ public CleanMissingEpisodesEntryPoint(ILibraryManager libraryManager, IServerConfigurationManager config, ILogger logger, ILocalizationManager localization, IFileSystem fileSystem, ITaskManager taskManager)
+ {
+ _libraryManager = libraryManager;
+ _config = config;
+ _logger = logger;
+ _localization = localization;
+ _fileSystem = fileSystem;
+ _taskManager = taskManager;
+ }
+
+ private Timer LibraryUpdateTimer { get; set; }
+
+ public void Run()
+ {
+ _libraryManager.ItemAdded += _libraryManager_ItemAdded;
+ }
+
+ private void _libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
+ {
+ if (!FilterItem(e.Item))
+ {
+ return;
+ }
+
+ lock (_libraryChangedSyncLock)
+ {
+ if (LibraryUpdateTimer == null)
+ {
+ LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, Timeout.Infinite);
+ }
+ else
+ {
+ LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
+ }
+ }
+ }
+
+ private async void LibraryUpdateTimerCallback(object state)
+ {
+ if (MissingEpisodeProvider.IsRunning)
+ {
+ return;
+ }
+
+ if (_libraryManager.IsScanRunning)
+ {
+ return ;
+ }
+
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
+
+ }).Cast<Series>().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);
+ }
+
+ private bool FilterItem(BaseItem item)
+ {
+ return item is Episode && item.LocationType != LocationType.Virtual;
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ if (LibraryUpdateTimer != null)
+ {
+ LibraryUpdateTimer.Dispose();
+ LibraryUpdateTimer = null;
+ }
+
+ _libraryManager.ItemAdded -= _libraryManager_ItemAdded;
+ }
+ }
+ }
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
index 9d1684948..719779674 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.TV
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
list.AddRange(GetPosters(response.images).Select(i => new RemoteImageInfo
{
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
index d22827c25..36800202f 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs
@@ -16,7 +16,7 @@ namespace MediaBrowser.Providers.TV
{
public abstract class MovieDbProviderBase
{
- private const string EpisodeUrlPattern = @"http://api.themoviedb.org/3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos";
+ private const string EpisodeUrlPattern = @"https://api.themoviedb.org/3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos";
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _configurationManager;
private readonly IJsonSerializer _jsonSerializer;
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
index fe0bda828..2e51393e3 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.TV
{
public class MovieDbSeasonProvider : IRemoteMetadataProvider<Season, SeasonInfo>
{
- private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}/season/{1}?api_key={2}&append_to_response=images,keywords,external_ids,credits,videos";
+ private const string GetTvInfo3 = @"https://api.themoviedb.org/3/tv/{0}/season/{1}?api_key={2}&append_to_response=images,keywords,external_ids,credits,videos";
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _configurationManager;
private readonly IJsonSerializer _jsonSerializer;
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
index f7c19988c..65ac12adf 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
@@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.TV
{
- public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
+ public class MovieDbSeriesImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
@@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.TV
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
list.AddRange(GetPosters(results).Select(i => new RemoteImageInfo
{
@@ -196,9 +196,9 @@ namespace MediaBrowser.Providers.TV
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- return MovieDbSeriesProvider.Current.HasChanged(item, date);
+ return MovieDbSeriesProvider.Current.HasChanged(item);
}
}
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
index 98580396d..7d0f49955 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.TV
{
public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
- private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=credits,images,keywords,external_ids,videos,content_ratings";
+ private const string GetTvInfo3 = @"https://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=credits,images,keywords,external_ids,videos,content_ratings";
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
internal static MovieDbSeriesProvider Current { get; private set; }
@@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV
var obj = _jsonSerializer.DeserializeFromFile<RootObject>(dataFilePath);
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
var remoteResult = new RemoteSearchResult
{
@@ -414,7 +414,7 @@ namespace MediaBrowser.Providers.TV
return Path.Combine(path, filename);
}
- public bool HasChanged(IHasMetadata item, DateTime date)
+ public bool HasChanged(IHasMetadata item)
{
if (!MovieDbProvider.Current.GetTheMovieDbOptions().EnableAutomaticUpdates)
{
@@ -430,7 +430,7 @@ namespace MediaBrowser.Providers.TV
var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
- return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
@@ -438,7 +438,7 @@ namespace MediaBrowser.Providers.TV
private async Task<RemoteSearchResult> FindByExternalId(string id, string externalSource, CancellationToken cancellationToken)
{
- var url = string.Format("http://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
+ var url = string.Format("https://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
id,
MovieDbProvider.ApiKey,
externalSource);
@@ -460,7 +460,7 @@ namespace MediaBrowser.Providers.TV
if (tv != null)
{
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
- var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+ var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original";
var remoteResult = new RemoteSearchResult
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
index 49d41e06c..7a0b2c90c 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
@@ -17,7 +17,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbEpisodeImageProvider : IRemoteImageProvider, IHasChangeMonitor
+ public class TvdbEpisodeImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
{
private readonly IServerConfigurationManager _config;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
@@ -174,21 +174,18 @@ namespace MediaBrowser.Providers.TV
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- var episode = (Episode)item;
-
- if (!episode.IsVirtualUnaired)
+ // For non-unaired items, only enable if configured
+ if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
{
- // For non-unaired items, only enable if configured
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
+ return false;
}
if (!item.HasImage(ImageType.Primary))
{
+ var episode = (Episode)item;
+
var series = episode.Series;
if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
@@ -196,7 +193,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
- return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > date;
+ return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
index 291214fcd..509b22ee6 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.TV
/// <summary>
/// Class RemoteEpisodeProvider
/// </summary>
- class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasChangeMonitor
+ class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasItemChangeMonitor
{
private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
@@ -144,10 +144,9 @@ namespace MediaBrowser.Providers.TV
return result;
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- // Only enable for virtual items
- if (item.LocationType != LocationType.Virtual)
+ if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
{
return false;
}
@@ -160,7 +159,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var seriesXmlPath = TvdbSeriesProvider.Current.GetSeriesXmlPath(series.ProviderIds, series.GetPreferredMetadataLanguage());
- return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > date;
+ return _fileSystem.GetLastWriteTimeUtc(seriesXmlPath) > item.DateLastRefreshed;
}
return false;
@@ -750,7 +749,7 @@ namespace MediaBrowser.Providers.TV
private void AddPeople<T>(MetadataResult<T> result, string val, string personType)
{
// Sometimes tvdb actors have leading spaces
- foreach (var person in val.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries)
+ foreach (var person in val.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.Where(i => !string.IsNullOrWhiteSpace(i))
.Select(str => new PersonInfo { Type = personType, Name = str.Trim() }))
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
index 1c83d73fb..215e0640f 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
@@ -15,6 +15,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using CommonIO;
+using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Providers.TV
{
@@ -26,12 +27,12 @@ namespace MediaBrowser.Providers.TV
/// <summary>
/// The server time URL
/// </summary>
- private const string ServerTimeUrl = "http://thetvdb.com/api/Updates.php?type=none";
+ private const string ServerTimeUrl = "https://thetvdb.com/api/Updates.php?type=none";
/// <summary>
/// The updates URL
/// </summary>
- private const string UpdatesUrl = "http://thetvdb.com/api/Updates.php?type=all&time={0}";
+ private const string UpdatesUrl = "https://thetvdb.com/api/Updates.php?type=all&time={0}";
/// <summary>
/// The _HTTP client
@@ -89,7 +90,7 @@ namespace MediaBrowser.Providers.TV
var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
- _fileSystem.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
@@ -102,7 +103,7 @@ namespace MediaBrowser.Providers.TV
}
// Find out the last time we queried tvdb for updates
- var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
string newUpdateTime;
@@ -110,15 +111,21 @@ namespace MediaBrowser.Providers.TV
.Select(Path.GetFileName)
.ToList();
- var seriesIdsInLibrary = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is Series && !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
- .Cast<Series>()
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
+ }).Cast<Series>();
+
+ var seriesIdsInLibrary = seriesList
+ .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
.Select(i => i.GetProviderId(MetadataProviders.Tvdb))
.ToList();
var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase)
.ToList();
-
+
// If this is our first time, update all series
if (string.IsNullOrEmpty(lastUpdateTime))
{
@@ -157,7 +164,7 @@ namespace MediaBrowser.Providers.TV
await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false);
}
- _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
progress.Report(100);
}
@@ -300,10 +307,17 @@ namespace MediaBrowser.Providers.TV
var list = seriesIds.ToList();
var numComplete = 0;
+ var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true,
+ GroupByPresentationUniqueKey = false
+
+ }).Cast<Series>();
+
// Gather all series into a lookup by tvdb id
- var allSeries = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is Series && !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
- .Cast<Series>()
+ var allSeries = seriesList
+ .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
.ToLookup(i => i.GetProviderId(MetadataProviders.Tvdb));
foreach (var seriesId in list)
@@ -323,7 +337,7 @@ namespace MediaBrowser.Providers.TV
catch (HttpException ex)
{
_logger.ErrorException("Error updating tvdb series id {0}, language {1}", ex, seriesId, language);
-
+
// Already logged at lower levels, but don't fail the whole operation, unless timed out
// We have to fail this to make it run again otherwise new episode data could potentially be missing
if (ex.IsTimedOut)
@@ -357,7 +371,7 @@ namespace MediaBrowser.Providers.TV
seriesDataPath = Path.Combine(seriesDataPath, id);
- _fileSystem.CreateDirectory(seriesDataPath);
+ _fileSystem.CreateDirectory(seriesDataPath);
return TvdbSeriesProvider.Current.DownloadSeriesZip(id, MetadataProviders.Tvdb.ToString(), seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, cancellationToken);
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
index 5e7ce9f7e..52d12e501 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
@@ -20,7 +20,7 @@ using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor
+ public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasItemChangeMonitor
{
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -363,15 +363,11 @@ namespace MediaBrowser.Providers.TV
});
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
- if (item.LocationType != LocationType.Virtual)
+ if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
{
- // For non-virtual items, only enable if configured
- if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
- {
- return false;
- }
+ return false;
}
var season = (Season)item;
@@ -384,7 +380,7 @@ namespace MediaBrowser.Providers.TV
var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
- return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
+ return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed;
}
return false;
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index f66e9254e..ee1505b46 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -53,9 +53,9 @@ namespace MediaBrowser.Providers.TV
Current = this;
}
- private const string SeriesSearchUrl = "http://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
- private const string SeriesGetZip = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
- private const string GetSeriesByImdbId = "http://www.thetvdb.com/api/GetSeriesByRemoteID.php?imdbid={0}&language={1}";
+ private const string SeriesSearchUrl = "https://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
+ private const string SeriesGetZip = "https://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
+ private const string GetSeriesByImdbId = "https://www.thetvdb.com/api/GetSeriesByRemoteID.php?imdbid={0}&language={1}";
private string NormalizeLanguage(string language)
{
@@ -1465,4 +1465,4 @@ namespace MediaBrowser.Providers.TV
};
}
}
-} \ No newline at end of file
+}
diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs
index 82baae250..f5a26ba0a 100644
--- a/MediaBrowser.Providers/TV/TvExternalIds.cs
+++ b/MediaBrowser.Providers/TV/TvExternalIds.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.TV
public string UrlFormatString
{
- get { return "http://thetvdb.com/index.php?tab=series&id={0}"; }
+ get { return "https://thetvdb.com/index.php?tab=series&id={0}"; }
}
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
index 85ab76182..b0e05a5bc 100644
--- a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
+++ b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs
@@ -27,11 +27,11 @@ namespace MediaBrowser.Server.Implementations.Activity
_appPaths = appPaths;
}
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "activitylog.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index c9956c68a..6a9842cb2 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -133,7 +133,7 @@ namespace MediaBrowser.Server.Implementations.Channels
if (query.IsFavorite.HasValue)
{
var val = query.IsFavorite.Value;
- channels = channels.Where(i => _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite == val)
+ channels = channels.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val)
.ToList();
}
@@ -1437,7 +1437,7 @@ namespace MediaBrowser.Server.Implementations.Channels
case ItemFilter.IsFavoriteOrLikes:
return items.Where(item =>
{
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
if (userdata == null)
{
@@ -1453,7 +1453,7 @@ namespace MediaBrowser.Server.Implementations.Channels
case ItemFilter.Likes:
return items.Where(item =>
{
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
});
@@ -1461,7 +1461,7 @@ namespace MediaBrowser.Server.Implementations.Channels
case ItemFilter.Dislikes:
return items.Where(item =>
{
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
});
@@ -1469,7 +1469,7 @@ namespace MediaBrowser.Server.Implementations.Channels
case ItemFilter.IsFavorite:
return items.Where(item =>
{
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
return userdata != null && userdata.IsFavorite;
});
@@ -1477,7 +1477,7 @@ namespace MediaBrowser.Server.Implementations.Channels
case ItemFilter.IsResumable:
return items.Where(item =>
{
- var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = _userDataManager.GetUserData(user, item);
return userdata != null && userdata.PlaybackPositionTicks > 0;
});
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 2ee55edb9..dfbac47d5 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -115,11 +115,10 @@ namespace MediaBrowser.Server.Implementations.Dto
{
if (options.Fields.Contains(ItemFields.ItemCounts))
{
- var itemFilter = byName.GetItemFilter();
-
- var libraryItems = user != null ?
- user.RootFolder.GetRecursiveChildren(user, itemFilter) :
- _libraryManager.RootFolder.GetRecursiveChildren(itemFilter);
+ var libraryItems = byName.GetTaggedItems(new InternalItemsQuery(user)
+ {
+ Recursive = true
+ });
SetItemByNameInfo(item, dto, libraryItems.ToList(), user);
}
@@ -194,24 +193,13 @@ namespace MediaBrowser.Server.Implementations.Dto
private List<BaseItem> GetTaggedItems(IItemByName byName, User user)
{
- var person = byName as Person;
-
- if (person != null)
+ var items = byName.GetTaggedItems(new InternalItemsQuery(user)
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- Person = byName.Name
-
- }, new string[] { });
-
- return items.ToList();
- }
+ Recursive = true
- var itemFilter = byName.GetItemFilter();
+ }).ToList();
- return user != null ?
- user.RootFolder.GetRecursiveChildren(user, itemFilter).ToList() :
- _libraryManager.RootFolder.GetRecursiveChildren(itemFilter).ToList();
+ return items;
}
private SyncedItemProgress[] GetSyncedItemProgress(DtoOptions options)
@@ -282,7 +270,7 @@ namespace MediaBrowser.Server.Implementations.Dto
else if (dto.HasSyncJob.Value)
{
- dto.SyncStatus = SyncJobItemStatus.Queued;
+ dto.SyncStatus = syncProgress.Where(i => string.Equals(i.ItemId, dto.Id, StringComparison.OrdinalIgnoreCase)).Select(i => i.Status).Max();
}
}
}
@@ -307,7 +295,7 @@ namespace MediaBrowser.Server.Implementations.Dto
else if (dto.HasSyncJob.Value)
{
- dto.SyncStatus = SyncJobItemStatus.Queued;
+ dto.SyncStatus = syncProgress.Where(i => string.Equals(i.ItemId, dto.Id, StringComparison.OrdinalIgnoreCase)).Select(i => i.Status).Max();
}
}
}
@@ -397,12 +385,6 @@ namespace MediaBrowser.Server.Implementations.Dto
collectionFolder.GetViewType(user);
}
- var playlist = item as Playlist;
- if (playlist != null)
- {
- AttachLinkedChildImages(dto, playlist, user, options);
- }
-
if (fields.Contains(ItemFields.CanDelete))
{
dto.CanDelete = user == null
@@ -487,7 +469,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
if (item.IsFolder)
{
- var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey());
+ var userData = _userDataRepository.GetUserData(user, 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
@@ -499,13 +481,22 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.ChildCount = GetChildCount(folder, user);
- // These are just far too slow.
- if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is ICollectionFolder))
+ if (folder.SupportsUserDataFromChildren)
{
SetSpecialCounts(folder, user, dto, fields, syncProgress);
}
}
+ if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
+ {
+ dto.CumulativeRunTimeTicks = item.RunTimeTicks;
+ }
+
+ if (fields.Contains(ItemFields.DateLastMediaAdded))
+ {
+ dto.DateLastMediaAdded = folder.DateLastMediaAdded;
+ }
+
dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100;
}
@@ -626,9 +617,12 @@ namespace MediaBrowser.Server.Implementations.Dto
{
if (!string.IsNullOrEmpty(item.Album))
{
- var parentAlbum = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is MusicAlbum && string.Equals(i.Name, item.Album, StringComparison.OrdinalIgnoreCase))
- .FirstOrDefault();
+ var parentAlbum = _libraryManager.GetItemList(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
+ Name = item.Album
+
+ }).FirstOrDefault();
if (parentAlbum != null)
{
@@ -1363,9 +1357,10 @@ namespace MediaBrowser.Server.Implementations.Dto
if (fields.Contains(ItemFields.MediaSourceCount))
{
- if (video.MediaSourceCount != 1)
+ var mediaSourceCount = video.MediaSourceCount;
+ if (mediaSourceCount != 1)
{
- dto.MediaSourceCount = video.MediaSourceCount;
+ dto.MediaSourceCount = mediaSourceCount;
}
}
@@ -1564,45 +1559,6 @@ namespace MediaBrowser.Server.Implementations.Dto
}
}
- private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user, DtoOptions options)
- {
- List<BaseItem> linkedChildren = null;
-
- var backdropLimit = options.GetImageLimit(ImageType.Backdrop);
-
- if (backdropLimit > 0 && dto.BackdropImageTags.Count == 0)
- {
- linkedChildren = user == null
- ? folder.GetRecursiveChildren().ToList()
- : folder.GetRecursiveChildren(user).ToList();
-
- var parentWithBackdrop = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Backdrop).Any());
-
- if (parentWithBackdrop != null)
- {
- dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop);
- dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop, backdropLimit);
- }
- }
-
- if (!dto.ImageTags.ContainsKey(ImageType.Primary) && options.GetImageLimit(ImageType.Primary) > 0)
- {
- if (linkedChildren == null)
- {
- linkedChildren = user == null
- ? folder.GetRecursiveChildren().ToList()
- : folder.GetRecursiveChildren(user).ToList();
- }
- var parentWithImage = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Primary).Any());
-
- if (parentWithImage != null)
- {
- dto.ParentPrimaryImageItemId = GetDtoId(parentWithImage);
- dto.ParentPrimaryImageTag = GetImageCacheTag(parentWithImage, ImageType.Primary);
- }
- }
- }
-
private string GetMappedPath(IHasMetadata item)
{
var path = item.Path;
@@ -1658,9 +1614,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
var recursiveItemCount = 0;
var unplayed = 0;
- long runtime = 0;
- DateTime? dateLastMediaAdded = null;
double totalPercentPlayed = 0;
double totalSyncPercent = 0;
var addSyncInfo = fields.Contains(ItemFields.SyncInfo);
@@ -1677,16 +1631,7 @@ namespace MediaBrowser.Server.Implementations.Dto
// Loop through each recursive child
foreach (var child in children)
{
- if (!dateLastMediaAdded.HasValue)
- {
- dateLastMediaAdded = child.DateCreated;
- }
- else
- {
- dateLastMediaAdded = new[] { dateLastMediaAdded.Value, child.DateCreated }.Max();
- }
-
- var userdata = _userDataRepository.GetUserData(user.Id, child.GetUserDataKey());
+ var userdata = _userDataRepository.GetUserData(user, child);
recursiveItemCount++;
@@ -1714,8 +1659,6 @@ namespace MediaBrowser.Server.Implementations.Dto
unplayed++;
}
- runtime += child.RunTimeTicks ?? 0;
-
if (addSyncInfo)
{
double percent = 0;
@@ -1754,16 +1697,6 @@ namespace MediaBrowser.Server.Implementations.Dto
}
}
}
-
- if (runtime > 0 && fields.Contains(ItemFields.CumulativeRunTimeTicks))
- {
- dto.CumulativeRunTimeTicks = runtime;
- }
-
- if (fields.Contains(ItemFields.DateLastMediaAdded))
- {
- dto.DateLastMediaAdded = dateLastMediaAdded;
- }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
index 71019e0ad..e84b66c5a 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
@@ -215,6 +215,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
return;
}
+ var video = e.Item as Video;
+ if (video != null && video.IsThemeMedia)
+ {
+ return;
+ }
+
var type = GetPlaybackNotificationType(item.MediaType);
SendPlaybackNotification(type, e);
@@ -230,6 +236,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
return;
}
+ var video = e.Item as Video;
+ if (video != null && video.IsThemeMedia)
+ {
+ return;
+ }
+
var type = GetPlaybackStoppedNotificationType(item.MediaType);
SendPlaybackNotification(type, e);
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index e45df3f4a..f402a0a33 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -116,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
premiereDate,
options,
overwriteExisting,
- false,
+ false,
result,
cancellationToken).ConfigureAwait(false);
}
@@ -202,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
null,
options,
true,
- request.RememberCorrection,
+ request.RememberCorrection,
result,
cancellationToken).ConfigureAwait(false);
@@ -219,7 +219,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
DateTime? premiereDate,
AutoOrganizeOptions options,
bool overwriteExisting,
- bool rememberCorrection,
+ bool rememberCorrection,
FileOrganizationResult result,
CancellationToken cancellationToken)
{
@@ -242,7 +242,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
premiereDate,
options,
overwriteExisting,
- rememberCorrection,
+ rememberCorrection,
result,
cancellationToken);
}
@@ -255,7 +255,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
DateTime? premiereDate,
AutoOrganizeOptions options,
bool overwriteExisting,
- bool rememberCorrection,
+ bool rememberCorrection,
FileOrganizationResult result,
CancellationToken cancellationToken)
{
@@ -304,7 +304,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (otherDuplicatePaths.Count > 0)
{
- var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, otherDuplicatePaths);
+ var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths));
_logger.Info(msg);
result.Status = FileSortingStatus.SkippedExisting;
result.StatusMessage = msg;
@@ -536,7 +536,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
result.ExtractedName = nameWithoutYear;
result.ExtractedYear = yearInName;
- var series = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Series)
+ var series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true
+ })
.Cast<Series>()
.Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
.Where(i => i.Item2 > 0)
@@ -550,10 +554,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (info != null)
{
- series = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is Series)
- .Cast<Series>()
- .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase));
+ series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Recursive = true
+ }).Cast<Series>()
+ .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase));
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 25463b660..c5cb810e5 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -179,6 +179,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
{
+ if (_disposed)
+ {
+ return;
+ }
+
if (WebSocketConnecting != null)
{
WebSocketConnecting(this, args);
@@ -187,6 +192,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private void OnWebSocketConnected(WebSocketConnectEventArgs args)
{
+ if (_disposed)
+ {
+ return;
+ }
+
if (WebSocketConnected != null)
{
WebSocketConnected(this, args);
@@ -331,6 +341,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var httpRes = httpReq.Response;
+ if (_disposed)
+ {
+ httpRes.StatusCode = 503;
+ httpRes.Close();
+ return Task.FromResult(true);
+ }
+
var operationName = httpReq.OperationName;
var localPath = url.LocalPath;
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 13a06afc2..09ca134d1 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -663,7 +663,7 @@ namespace MediaBrowser.Server.Implementations.IO
while (item == null && !string.IsNullOrEmpty(path))
{
- item = LibraryManager.FindByPath(path);
+ item = LibraryManager.FindByPath(path, null);
path = Path.GetDirectoryName(path);
}
diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
index 9ebae5d91..49012c65a 100644
--- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
+++ b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
@@ -102,15 +102,10 @@ namespace MediaBrowser.Server.Implementations.Intros
if (trailerTypes.Count > 0)
{
- var excludeTrailerTypes = Enum.GetNames(typeof(TrailerType))
- .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true))
- .Except(trailerTypes)
- .ToArray();
-
var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Trailer).Name },
- ExcludeTrailerTypes = excludeTrailerTypes
+ TrailerTypes = trailerTypes.ToArray()
});
candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index ccba293a3..1407cdce3 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -143,6 +143,7 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
private readonly Func<IProviderManager> _providerManagerFactory;
private readonly Func<IUserViewManager> _userviewManager;
+ public bool IsScanRunning { get; private set; }
/// <summary>
/// The _library items cache
@@ -305,9 +306,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken)
{
- var seasons = RootFolder.GetRecursiveChildren(i => i is Season)
- .Cast<Season>()
- .Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value == 0 && !string.Equals(i.Name, newName, StringComparison.Ordinal))
+ var seasons = GetItemList(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Season).Name },
+ Recursive = true,
+ IndexNumber = 0
+
+ }).Cast<Season>()
+ .Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal))
.ToList();
foreach (var season in seasons)
@@ -521,29 +527,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("items");
}
- var dict = new Dictionary<Guid, BaseItem>();
-
- foreach (var item in items)
- {
- var video = item as Video;
-
- if (video != null)
- {
- if (video.PrimaryVersionId.HasValue)
- {
- var primary = GetItemById(video.PrimaryVersionId.Value) as Video;
-
- if (primary != null)
- {
- dict[primary.Id] = primary;
- continue;
- }
- }
- }
- dict[item.Id] = item;
- }
-
- return dict.Values;
+ return items.DistinctBy(i => i.PresentationUniqueKey, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
@@ -800,27 +784,22 @@ namespace MediaBrowser.Server.Implementations.Library
return _userRootFolder;
}
- public BaseItem FindByPath(string path)
+ public BaseItem FindByPath(string path, bool? isFolder)
{
var query = new InternalItemsQuery
{
- Path = path
+ Path = path,
+ IsFolder = isFolder
};
- // Only use the database result if there's exactly one item, otherwise we run the risk of returning old data that hasn't been cleaned yet.
- var items = GetItemIds(query).Select(GetItemById).Where(i => i != null).ToArray();
+ // If this returns multiple items it could be tricky figuring out which one is correct.
+ // In most cases, the newest one will be and the others obsolete but not yet cleaned up
- if (items.Length == 1)
- {
- return items[0];
- }
-
- if (items.Length == 0)
- {
- return null;
- }
-
- return RootFolder.FindByPath(path);
+ return GetItemIds(query)
+ .Select(GetItemById)
+ .Where(i => i != null)
+ .OrderByDescending(i => i.DateCreated)
+ .FirstOrDefault();
}
/// <summary>
@@ -929,7 +908,10 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("name");
}
- var validFilename = _fileSystem.GetValidFilename(name).Trim();
+ // Trim the period at the end because windows will have a hard time with that
+ var validFilename = _fileSystem.GetValidFilename(name)
+ .Trim()
+ .TrimEnd('.');
string subFolderPrefix = null;
@@ -951,31 +933,25 @@ namespace MediaBrowser.Server.Implementations.Library
Path.Combine(path, validFilename) :
Path.Combine(path, subFolderPrefix, validFilename);
- var id = GetNewItemId(fullPath, type);
-
- BaseItem obj;
-
- if (!_libraryItemsCache.TryGetValue(id, out obj))
- {
- obj = CreateItemByName<T>(fullPath, name, id);
-
- RegisterItem(id, obj);
- }
-
- return obj as T;
+ return CreateItemByName<T>(fullPath, name);
}
- private T CreateItemByName<T>(string path, string name, Guid id)
+ private T CreateItemByName<T>(string path, string name)
where T : BaseItem, new()
{
var isArtist = typeof(T) == typeof(MusicArtist);
if (isArtist)
{
- var existing = RootFolder
- .GetRecursiveChildren(i => i is T && NameExtensions.AreEqual(i.Name, name))
- .Cast<T>()
- .FirstOrDefault();
+ var existing = GetItemList(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(T).Name },
+ Name = name
+
+ }).Cast<MusicArtist>()
+ .OrderBy(i => i.IsAccessedByName ? 1 : 0)
+ .Cast<T>()
+ .FirstOrDefault();
if (existing != null)
{
@@ -983,6 +959,8 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
+ var id = GetNewItemId(path, typeof(T));
+
var item = GetItemById(id) as T;
if (item == null)
@@ -996,11 +974,6 @@ namespace MediaBrowser.Server.Implementations.Library
Path = path
};
- if (isArtist)
- {
- (item as MusicArtist).IsAccessedByName = true;
- }
-
var task = CreateItem(item, CancellationToken.None);
Task.WaitAll(task);
}
@@ -1102,6 +1075,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
{
+ IsScanRunning = true;
_libraryMonitorFactory().Stop();
try
@@ -1111,6 +1085,7 @@ namespace MediaBrowser.Server.Implementations.Library
finally
{
_libraryMonitorFactory().Start();
+ IsScanRunning = false;
}
}
@@ -1369,12 +1344,20 @@ namespace MediaBrowser.Server.Implementations.Library
AddUserToQuery(query, query.User);
}
- var initialResult = ItemRepository.GetItemIds(query);
+ 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 new QueryResult<BaseItem>
{
- TotalRecordCount = initialResult.TotalRecordCount,
- Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray()
+ Items = ItemRepository.GetItemIdsList(query).Select(GetItemById).Where(i => i != null).ToArray()
};
}
@@ -1413,7 +1396,7 @@ namespace MediaBrowser.Server.Implementations.Library
private void AddUserToQuery(InternalItemsQuery query, User user)
{
- if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0)
+ if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0 && string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
{
var userViews = _userviewManager().GetUserViews(new UserViewQuery
{
@@ -2576,5 +2559,175 @@ namespace MediaBrowser.Server.Implementations.Library
throw new InvalidOperationException();
}
+
+ public void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, bool refreshLibrary)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ name = _fileSystem.GetValidFilename(name);
+
+ var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+
+ var virtualFolderPath = Path.Combine(rootFolderPath, name);
+ while (_fileSystem.DirectoryExists(virtualFolderPath))
+ {
+ name += "1";
+ virtualFolderPath = Path.Combine(rootFolderPath, name);
+ }
+
+ if (mediaPaths != null)
+ {
+ var invalidpath = mediaPaths.FirstOrDefault(i => !_fileSystem.DirectoryExists(i));
+ if (invalidpath != null)
+ {
+ throw new ArgumentException("The specified path does not exist: " + invalidpath + ".");
+ }
+ }
+
+ _libraryMonitorFactory().Stop();
+
+ try
+ {
+ _fileSystem.CreateDirectory(virtualFolderPath);
+
+ if (!string.IsNullOrEmpty(collectionType))
+ {
+ var path = Path.Combine(virtualFolderPath, collectionType + ".collection");
+
+ using (File.Create(path))
+ {
+
+ }
+ }
+
+ if (mediaPaths != null)
+ {
+ foreach (var path in mediaPaths)
+ {
+ AddMediaPath(name, path);
+ }
+ }
+ }
+ finally
+ {
+ Task.Run(() =>
+ {
+ // No need to start if scanning the library because it will handle it
+ if (refreshLibrary)
+ {
+ ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+ }
+ else
+ {
+ // Need to add a delay here or directory watchers may still pick up the changes
+ var task = Task.Delay(1000);
+ // Have to block here to allow exceptions to bubble
+ Task.WaitAll(task);
+
+ _libraryMonitorFactory().Start();
+ }
+ });
+ }
+ }
+
+ public void RemoveVirtualFolder(string name, bool refreshLibrary)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+
+ var path = Path.Combine(rootFolderPath, name);
+
+ if (!_fileSystem.DirectoryExists(path))
+ {
+ throw new DirectoryNotFoundException("The media folder does not exist");
+ }
+
+ _libraryMonitorFactory().Stop();
+
+ try
+ {
+ _fileSystem.DeleteDirectory(path, true);
+ }
+ finally
+ {
+ Task.Run(() =>
+ {
+ // No need to start if scanning the library because it will handle it
+ if (refreshLibrary)
+ {
+ ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+ }
+ else
+ {
+ // Need to add a delay here or directory watchers may still pick up the changes
+ var task = Task.Delay(1000);
+ // Have to block here to allow exceptions to bubble
+ Task.WaitAll(task);
+
+ _libraryMonitorFactory().Start();
+ }
+ });
+ }
+ }
+
+ private const string ShortcutFileExtension = ".mblink";
+ private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
+ public void AddMediaPath(string virtualFolderName, string path)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ if (!_fileSystem.DirectoryExists(path))
+ {
+ throw new DirectoryNotFoundException("The path does not exist.");
+ }
+
+ var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+ var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
+
+ var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path);
+
+ var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
+
+ while (_fileSystem.FileExists(lnk))
+ {
+ shortcutFilename += "1";
+ lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
+ }
+
+ _fileSystem.CreateShortcut(lnk, path);
+ }
+
+ public void RemoveMediaPath(string virtualFolderName, string mediaPath)
+ {
+ if (string.IsNullOrWhiteSpace(mediaPath))
+ {
+ throw new ArgumentNullException("mediaPath");
+ }
+
+ var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+ var path = Path.Combine(rootFolderPath, virtualFolderName);
+
+ if (!_fileSystem.DirectoryExists(path))
+ {
+ throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
+ }
+
+ var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
+
+ if (!string.IsNullOrEmpty(shortcut))
+ {
+ _fileSystem.DeleteFile(shortcut);
+ }
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
index 96d570ef9..78107b82d 100644
--- a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
@@ -6,6 +6,8 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -22,18 +24,24 @@ namespace MediaBrowser.Server.Implementations.Library
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var items = _libraryManager.RootFolder
- .GetRecursiveChildren(i => i is IHasTrailers)
- .Cast<IHasTrailers>()
- .ToList();
+ var items = _libraryManager.GetItemList(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name },
+ Recursive = true
+
+ }).OfType<IHasTrailers>().ToList();
+
+ var trailerTypes = Enum.GetNames(typeof(TrailerType))
+ .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true))
+ .Except(new[] { TrailerType.LocalTrailer })
+ .ToArray();
var trailers = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Trailer).Name },
- ExcludeTrailerTypes = new[]
- {
- TrailerType.LocalTrailer
- }
+ TrailerTypes = trailerTypes,
+ Recursive = true
+
}).ToArray();
var numComplete = 0;
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 95f5cb0e1..a47fcdf4f 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -267,15 +267,17 @@ namespace MediaBrowser.Server.Implementations.Library
private void SetUserProperties(IHasUserData item, MediaSourceInfo source, User user)
{
- var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user, item);
- SetDefaultAudioStreamIndex(source, userData, user);
- SetDefaultSubtitleStreamIndex(source, userData, user);
+ var allowRememberingSelection = item == null || item.EnableRememberingTrackSelections;
+
+ SetDefaultAudioStreamIndex(source, userData, user, allowRememberingSelection);
+ SetDefaultSubtitleStreamIndex(source, userData, user, allowRememberingSelection);
}
- private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user)
+ private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
{
- if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None)
+ if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
{
var index = userData.SubtitleStreamIndex.Value;
// Make sure the saved index is still valid
@@ -304,9 +306,9 @@ namespace MediaBrowser.Server.Implementations.Library
user.Configuration.SubtitleMode, audioLangage);
}
- private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user)
+ private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
{
- if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections)
+ if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
{
var index = userData.AudioStreamIndex.Value;
// Make sure the saved index is still valid
diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
index aad7c112b..c82c4cdf7 100644
--- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
@@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user)
{
var genres = item
- .GetRecursiveChildren(user, i => i is Audio)
+ .GetRecursiveChildren(user, i => i is Audio)
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
index 61a5d98a3..e271fbcb2 100644
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
@@ -87,13 +87,16 @@ namespace MediaBrowser.Server.Implementations.Library
{
var searchTerm = query.SearchTerm;
+ if (searchTerm != null)
+ {
+ searchTerm = searchTerm.Trim().RemoveDiacritics();
+ }
+
if (string.IsNullOrWhiteSpace(searchTerm))
{
throw new ArgumentNullException("searchTerm");
}
- searchTerm = searchTerm.Trim().RemoveDiacritics();
-
var terms = GetWords(searchTerm);
var hints = new List<Tuple<BaseItem, string, int>>();
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
index ae737d244..0e211937f 100644
--- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -22,7 +23,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
public event EventHandler<UserDataSaveEventArgs> UserDataSaved;
- private readonly ConcurrentDictionary<string, UserItemData> _userData = new ConcurrentDictionary<string, UserItemData>();
+ private readonly Dictionary<string, UserItemData> _userData = new Dictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
@@ -56,27 +57,32 @@ namespace MediaBrowser.Server.Implementations.Library
cancellationToken.ThrowIfCancellationRequested();
- var key = item.GetUserDataKey();
+ var keys = item.GetUserDataKeys();
- try
+ foreach (var key in keys)
{
- await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
+ try
+ {
+ await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
- var newValue = userData;
+ var newValue = userData;
- // Once it succeeds, put it into the dictionary to make it available to everyone else
- _userData.AddOrUpdate(GetCacheKey(userId, key), newValue, delegate { return newValue; });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving user data", ex);
+ lock (_userData)
+ {
+ _userData[GetCacheKey(userId, key)] = newValue;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error saving user data", ex);
- throw;
+ throw;
+ }
}
EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs
{
- Key = key,
+ Keys = keys,
UserData = userData,
SaveReason = reason,
UserId = userId,
@@ -134,6 +140,54 @@ namespace MediaBrowser.Server.Implementations.Library
return Repository.GetAllUserData(userId);
}
+ public UserItemData GetUserData(Guid userId, List<string> keys)
+ {
+ if (userId == Guid.Empty)
+ {
+ throw new ArgumentNullException("userId");
+ }
+ if (keys == null)
+ {
+ throw new ArgumentNullException("keys");
+ }
+
+ lock (_userData)
+ {
+ foreach (var key in keys)
+ {
+ var cacheKey = GetCacheKey(userId, key);
+ UserItemData value;
+ if (_userData.TryGetValue(cacheKey, out value))
+ {
+ return value;
+ }
+
+ value = Repository.GetUserData(userId, key);
+
+ if (value != null)
+ {
+ _userData[cacheKey] = value;
+ return value;
+ }
+ }
+
+ if (keys.Count > 0)
+ {
+ var key = keys[0];
+ var cacheKey = GetCacheKey(userId, key);
+ var userdata = new UserItemData
+ {
+ UserId = userId,
+ Key = key
+ };
+ _userData[cacheKey] = userdata;
+ return userdata;
+ }
+
+ return null;
+ }
+ }
+
/// <summary>
/// Gets the user data.
/// </summary>
@@ -151,14 +205,29 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("key");
}
- return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => GetUserDataFromRepository(userId, key));
- }
+ lock (_userData)
+ {
+ var cacheKey = GetCacheKey(userId, key);
+ UserItemData value;
+ if (_userData.TryGetValue(cacheKey, out value))
+ {
+ return value;
+ }
- public UserItemData GetUserDataFromRepository(Guid userId, string key)
- {
- var data = Repository.GetUserData(userId, key);
+ value = Repository.GetUserData(userId, key);
- return data;
+ if (value == null)
+ {
+ value = new UserItemData
+ {
+ UserId = userId,
+ Key = key
+ };
+ }
+
+ _userData[cacheKey] = value;
+ return value;
+ }
}
/// <summary>
@@ -172,9 +241,24 @@ namespace MediaBrowser.Server.Implementations.Library
return userId + key;
}
+ public UserItemData GetUserData(IHasUserData user, IHasUserData item)
+ {
+ return GetUserData(user.Id, item);
+ }
+
+ public UserItemData GetUserData(string userId, IHasUserData item)
+ {
+ return GetUserData(new Guid(userId), item);
+ }
+
+ public UserItemData GetUserData(Guid userId, IHasUserData item)
+ {
+ return GetUserData(userId, item.GetUserDataKeys());
+ }
+
public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
{
- var userData = GetUserData(user.Id, item.GetUserDataKey());
+ var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
item.FillUserDataDtoValues(dto, userData, user);
@@ -261,10 +345,5 @@ namespace MediaBrowser.Server.Implementations.Library
return playedToCompletion;
}
-
- public UserItemData GetUserData(string userId, string key)
- {
- return GetUserData(new Guid(userId), key);
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
index c122d64d3..c1803b5e4 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var items = _libraryManager.RootFolder.GetRecursiveChildren()
+ var items = _libraryManager.RootFolder.GetRecursiveChildren(i => true)
.SelectMany(i => i.Studios)
.DistinctNames()
.ToList();
@@ -73,28 +73,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
progress.Report(percent);
}
- var allIds = _libraryManager.GetItemIds(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Studio).Name }
- });
-
- var invalidIds = allIds
- .Except(validIds)
- .ToList();
-
- foreach (var id in invalidIds)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var item = _libraryManager.GetItemById(id);
-
- await _libraryManager.DeleteItem(item, new DeleteOptions
- {
- DeleteFileLocation = false
-
- }).ConfigureAwait(false);
- }
-
progress.Report(100);
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
index 5ea5fb254..7f52a4506 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
@@ -20,16 +20,12 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- var allYears = _libraryManager.RootFolder.GetRecursiveChildren(i => i.ProductionYear.HasValue)
- .Select(i => i.ProductionYear ?? -1)
- .Where(i => i > 0)
- .Distinct()
- .ToList();
-
- var count = allYears.Count;
+ var yearNumber = 1900;
+ var maxYear = DateTime.UtcNow.Year + 3;
+ var count = maxYear - yearNumber + 1;
var numComplete = 0;
- foreach (var yearNumber in allYears)
+ while (yearNumber < maxYear)
{
try
{
@@ -53,6 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
percent *= 100;
progress.Report(percent);
+ yearNumber++;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 3c7ee55b7..b21aa904b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -23,6 +23,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_fileSystem = fileSystem;
}
+ public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile)
+ {
+ return targetFile;
+ }
+
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
var httpRequestOptions = new HttpRequestOptions()
@@ -42,10 +47,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Copying recording stream to file {0}", targetFile);
- var durationToken = new CancellationTokenSource(duration);
- var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ 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);
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ }
- await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken).ConfigureAwait(false);
+ await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 60ff23b04..2de51479f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -26,7 +26,10 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Power;
using Microsoft.Win32;
@@ -40,7 +43,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly IServerConfigurationManager _config;
private readonly IJsonSerializer _jsonSerializer;
- private readonly ItemDataProvider<RecordingInfo> _recordingProvider;
private readonly ItemDataProvider<SeriesTimerInfo> _seriesTimerProvider;
private readonly TimerManager _timerProvider;
@@ -56,6 +58,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public static EmbyTV Current;
+ public event EventHandler DataSourceChanged;
+ public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
+
+ private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
+ new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
+
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
{
Current = this;
@@ -74,10 +82,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
- _recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
_seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
_timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), powerManagement, _logger);
_timerProvider.TimerFired += _timerProvider_TimerFired;
+
+ _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
+ }
+
+ private void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
+ {
+ if (string.Equals(e.Key, "livetv", StringComparison.OrdinalIgnoreCase))
+ {
+ OnRecordingFoldersChanged();
+ }
}
public void Start()
@@ -85,6 +102,95 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.RestartTimers();
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+
+ CreateRecordingFolders();
+ }
+
+ private void OnRecordingFoldersChanged()
+ {
+ CreateRecordingFolders();
+ }
+
+ private void CreateRecordingFolders()
+ {
+ var recordingFolders = GetRecordingFolders();
+
+ var defaultRecordingPath = DefaultRecordingPath;
+ if (!recordingFolders.Any(i => i.Locations.Contains(defaultRecordingPath, StringComparer.OrdinalIgnoreCase)))
+ {
+ RemovePathFromLibrary(defaultRecordingPath);
+ }
+
+ var virtualFolders = _libraryManager.GetVirtualFolders()
+ .ToList();
+
+ var allExistingPaths = virtualFolders.SelectMany(i => i.Locations).ToList();
+
+ foreach (var recordingFolder in recordingFolders)
+ {
+ var pathsToCreate = recordingFolder.Locations
+ .Where(i => !allExistingPaths.Contains(i, StringComparer.OrdinalIgnoreCase))
+ .ToList();
+
+ if (pathsToCreate.Count == 0)
+ {
+ continue;
+ }
+
+ try
+ {
+ _libraryManager.AddVirtualFolder(recordingFolder.Name, recordingFolder.CollectionType, pathsToCreate.ToArray(), true);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error creating virtual folder", ex);
+ }
+ }
+ }
+
+ private void RemovePathFromLibrary(string path)
+ {
+ var requiresRefresh = false;
+ var virtualFolders = _libraryManager.GetVirtualFolders()
+ .ToList();
+
+ foreach (var virtualFolder in virtualFolders)
+ {
+ if (!virtualFolder.Locations.Contains(path, StringComparer.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ if (virtualFolder.Locations.Count == 1)
+ {
+ // remove entire virtual folder
+ try
+ {
+ _libraryManager.RemoveVirtualFolder(virtualFolder.Name, true);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error removing virtual folder", ex);
+ }
+ }
+ else
+ {
+ try
+ {
+ _libraryManager.RemoveMediaPath(virtualFolder.Name, path);
+ requiresRefresh = true;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error removing media path", ex);
+ }
+ }
+ }
+
+ if (requiresRefresh)
+ {
+ _libraryManager.ValidateMediaLibrary(new Progress<Double>(), CancellationToken.None);
+ }
}
void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
@@ -97,13 +203,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- public event EventHandler DataSourceChanged;
-
- public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
-
- private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
- new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
-
public string Name
{
get { return "Emby"; }
@@ -114,6 +213,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "livetv"); }
}
+ private string DefaultRecordingPath
+ {
+ get
+ {
+ return Path.Combine(DataPath, "recordings");
+ }
+ }
+
+ private string RecordingPath
+ {
+ get
+ {
+ var path = GetConfiguration().RecordingPath;
+
+ return string.IsNullOrWhiteSpace(path)
+ ? DefaultRecordingPath
+ : path;
+ }
+ }
+
public string HomePageUrl
{
get { return "http://emby.media"; }
@@ -280,49 +399,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return Task.FromResult(true);
}
- public async Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken)
+ public Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken)
{
- var remove = _recordingProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, recordingId, StringComparison.OrdinalIgnoreCase));
- if (remove != null)
- {
- if (!string.IsNullOrWhiteSpace(remove.TimerId))
- {
- var enableDelay = _activeRecordings.ContainsKey(remove.TimerId);
-
- CancelTimerInternal(remove.TimerId);
-
- if (enableDelay)
- {
- // A hack yes, but need to make sure the file is closed before attempting to delete it
- await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
- }
- }
-
- if (!string.IsNullOrWhiteSpace(remove.Path))
- {
- try
- {
- _fileSystem.DeleteFile(remove.Path);
- }
- catch (DirectoryNotFoundException)
- {
-
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting recording file {0}", ex, remove.Path);
- }
- }
- _recordingProvider.Delete(remove);
- }
- else
- {
- throw new ResourceNotFoundException("Recording not found: " + recordingId);
- }
+ return Task.FromResult(true);
}
public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
@@ -424,29 +503,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{
- var recordings = _recordingProvider.GetAll().ToList();
- var updated = false;
-
- foreach (var recording in recordings)
- {
- if (recording.Status == RecordingStatus.InProgress)
- {
- if (string.IsNullOrWhiteSpace(recording.TimerId) || !_activeRecordings.ContainsKey(recording.TimerId))
- {
- recording.Status = RecordingStatus.Cancelled;
- recording.DateLastUpdated = DateTime.UtcNow;
- _recordingProvider.Update(recording);
- updated = true;
- }
- }
- }
-
- if (updated)
- {
- recordings = _recordingProvider.GetAll().ToList();
- }
-
- return recordings;
+ return new List<RecordingInfo>();
}
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@@ -591,7 +648,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new ApplicationException("Tuner not found.");
}
- private async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
+ private async Task<Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
@@ -599,7 +656,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
try
{
- return await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+ var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+
+ return new Tuple<MediaSourceInfo, ITunerHost, SemaphoreSlim>(result.Item1, hostInstance, result.Item2);
}
catch (Exception e)
{
@@ -693,6 +752,106 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
+ private string GetRecordingPath(TimerInfo timer, ProgramInfo info)
+ {
+ var recordPath = RecordingPath;
+ var config = GetConfiguration();
+
+ if (info.IsMovie)
+ {
+ var customRecordingPath = config.MovieRecordingPath;
+ var allowSubfolder = true;
+ if (!string.IsNullOrWhiteSpace(customRecordingPath))
+ {
+ allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
+ recordPath = customRecordingPath;
+ }
+
+ if (allowSubfolder && config.EnableRecordingSubfolders)
+ {
+ recordPath = Path.Combine(recordPath, "Movies");
+ }
+
+ var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
+ if (info.ProductionYear.HasValue)
+ {
+ folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
+ }
+ recordPath = Path.Combine(recordPath, folderName);
+ }
+ else if (info.IsSeries)
+ {
+ var customRecordingPath = config.SeriesRecordingPath;
+ var allowSubfolder = true;
+ if (!string.IsNullOrWhiteSpace(customRecordingPath))
+ {
+ allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase);
+ recordPath = customRecordingPath;
+ }
+
+ if (allowSubfolder && config.EnableRecordingSubfolders)
+ {
+ recordPath = Path.Combine(recordPath, "Series");
+ }
+
+ var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
+ var folderNameWithYear = folderName;
+ if (info.ProductionYear.HasValue)
+ {
+ folderNameWithYear += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
+ }
+
+ if (Directory.Exists(Path.Combine(recordPath, folderName)))
+ {
+ recordPath = Path.Combine(recordPath, folderName);
+ }
+ else
+ {
+ recordPath = Path.Combine(recordPath, folderNameWithYear);
+ }
+
+ if (info.SeasonNumber.HasValue)
+ {
+ folderName = string.Format("Season {0}", info.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture));
+ recordPath = Path.Combine(recordPath, folderName);
+ }
+ }
+ else if (info.IsKids)
+ {
+ if (config.EnableRecordingSubfolders)
+ {
+ recordPath = Path.Combine(recordPath, "Kids");
+ }
+
+ var folderName = _fileSystem.GetValidFilename(info.Name).Trim();
+ if (info.ProductionYear.HasValue)
+ {
+ folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")";
+ }
+ recordPath = Path.Combine(recordPath, folderName);
+ }
+ else if (info.IsSports)
+ {
+ if (config.EnableRecordingSubfolders)
+ {
+ recordPath = Path.Combine(recordPath, "Sports");
+ }
+ recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim());
+ }
+ else
+ {
+ if (config.EnableRecordingSubfolders)
+ {
+ recordPath = Path.Combine(recordPath, "Other");
+ }
+ recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim());
+ }
+
+ var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";
+
+ return Path.Combine(recordPath, recordingFileName);
+ }
+
private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
{
if (timer == null)
@@ -722,68 +881,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new InvalidOperationException(string.Format("Program with Id {0} not found", timer.ProgramId));
}
- var recordPath = RecordingPath;
-
- if (info.IsMovie)
- {
- recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name).Trim());
- }
- else if (info.IsSeries)
- {
- recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name).Trim());
- }
- else if (info.IsKids)
- {
- recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name).Trim());
- }
- else if (info.IsSports)
- {
- recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name).Trim());
- }
- else
- {
- recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name).Trim());
- }
-
- var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";
-
- recordPath = Path.Combine(recordPath, recordingFileName);
-
- var recordingId = info.Id.GetMD5().ToString("N");
- var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, recordingId, StringComparison.OrdinalIgnoreCase));
-
- if (recording == null)
- {
- recording = new RecordingInfo
- {
- ChannelId = info.ChannelId,
- Id = recordingId,
- StartDate = info.StartDate,
- EndDate = info.EndDate,
- Genres = info.Genres,
- IsKids = info.IsKids,
- IsLive = info.IsLive,
- IsMovie = info.IsMovie,
- IsHD = info.IsHD,
- IsNews = info.IsNews,
- IsPremiere = info.IsPremiere,
- IsSeries = info.IsSeries,
- IsSports = info.IsSports,
- IsRepeat = !info.IsPremiere,
- Name = info.Name,
- EpisodeTitle = info.EpisodeTitle,
- ProgramId = info.Id,
- ImagePath = info.ImagePath,
- ImageUrl = info.ImageUrl,
- OriginalAirDate = info.OriginalAirDate,
- Status = RecordingStatus.Scheduled,
- Overview = info.Overview,
- SeriesTimerId = timer.SeriesTimerId,
- TimerId = timer.Id,
- ShowId = info.ShowId
- };
- _recordingProvider.AddOrUpdate(recording);
- }
+ var recordPath = GetRecordingPath(timer, info);
+ var recordingStatus = RecordingStatus.New;
try
{
@@ -797,24 +896,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
//await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
- var duration = recordingEndDate - DateTime.UtcNow;
-
var recorder = await GetRecorder().ConfigureAwait(false);
- if (recorder is EncodedRecorder)
- {
- recordPath = Path.ChangeExtension(recordPath, ".mp4");
- }
+ recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id);
_fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath;
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
- recording.Path = recordPath;
- recording.Status = RecordingStatus.InProgress;
- recording.DateLastUpdated = DateTime.UtcNow;
- _recordingProvider.AddOrUpdate(recording);
+ var duration = recordingEndDate - DateTime.UtcNow;
_logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture));
@@ -823,20 +914,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
Action onStarted = () =>
{
- result.Item2.Release();
+ result.Item3.Release();
isResourceOpen = false;
};
+ var pathWithDuration = result.Item2.ApplyDuration(mediaStreamInfo.Path, duration);
+
+ // If it supports supplying duration via url
+ if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase))
+ {
+ mediaStreamInfo.Path = pathWithDuration;
+ mediaStreamInfo.RunTimeTicks = duration.Ticks;
+ }
+
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
- recording.Status = RecordingStatus.Completed;
+ recordingStatus = RecordingStatus.Completed;
_logger.Info("Recording completed: {0}", recordPath);
}
finally
{
if (isResourceOpen)
{
- result.Item2.Release();
+ result.Item3.Release();
}
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
@@ -845,12 +945,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
catch (OperationCanceledException)
{
_logger.Info("Recording stopped: {0}", recordPath);
- recording.Status = RecordingStatus.Completed;
+ recordingStatus = RecordingStatus.Completed;
}
catch (Exception ex)
{
_logger.ErrorException("Error recording to {0}", ex, recordPath);
- recording.Status = RecordingStatus.Error;
+ recordingStatus = RecordingStatus.Error;
}
finally
{
@@ -858,12 +958,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_activeRecordings.TryRemove(timer.Id, out removed);
}
- recording.DateLastUpdated = DateTime.UtcNow;
- _recordingProvider.AddOrUpdate(recording);
-
- if (recording.Status == RecordingStatus.Completed)
+ if (recordingStatus == RecordingStatus.Completed)
{
- OnSuccessfulRecording(recording);
+ OnSuccessfulRecording(info.IsSeries, recordPath);
_timerProvider.Delete(timer);
}
else if (DateTime.UtcNow < timer.EndDate)
@@ -876,7 +973,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
else
{
_timerProvider.Delete(timer);
- _recordingProvider.Delete(recording);
}
}
@@ -916,24 +1012,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private async Task<IRecorder> GetRecorder()
{
- if (GetConfiguration().EnableRecordingEncoding)
+ var config = GetConfiguration();
+
+ if (config.EnableRecordingEncoding)
{
var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false);
if (regInfo.IsValid)
{
- return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer);
+ return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config);
}
}
return new DirectRecorder(_logger, _httpClient, _fileSystem);
}
- private async void OnSuccessfulRecording(RecordingInfo recording)
+ private async void OnSuccessfulRecording(bool isSeries, string path)
{
if (GetConfiguration().EnableAutoOrganize)
{
- if (recording.IsSeries)
+ if (isSeries)
{
try
{
@@ -943,12 +1041,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager);
- var result = await organize.OrganizeEpisodeFile(recording.Path, CancellationToken.None).ConfigureAwait(false);
-
- if (result.Status == FileSortingStatus.Success)
- {
- _recordingProvider.Delete(recording);
- }
+ var result = await organize.OrganizeEpisodeFile(path, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -972,18 +1065,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return epgData.FirstOrDefault(p => Math.Abs(startDateTicks - p.StartDate.Ticks) <= TimeSpan.FromMinutes(3).Ticks);
}
- private string RecordingPath
- {
- get
- {
- var path = GetConfiguration().RecordingPath;
-
- return string.IsNullOrWhiteSpace(path)
- ? Path.Combine(DataPath, "recordings")
- : path;
- }
- }
-
private LiveTvOptions GetConfiguration()
{
return _config.GetConfiguration<LiveTvOptions>("livetv");
@@ -991,7 +1072,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers)
{
- var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList();
+ var newTimers = GetTimersForSeries(seriesTimer, epgData, true).ToList();
var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false);
@@ -1005,7 +1086,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (deleteInvalidTimers)
{
- var allTimers = GetTimersForSeries(seriesTimer, epgData, new List<RecordingInfo>())
+ var allTimers = GetTimersForSeries(seriesTimer, epgData, false)
.Select(i => i.Id)
.ToList();
@@ -1021,7 +1102,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms, IReadOnlyList<RecordingInfo> currentRecordings)
+ private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer,
+ IEnumerable<ProgramInfo> allPrograms,
+ bool filterByCurrentRecordings)
{
if (seriesTimer == null)
{
@@ -1031,23 +1114,73 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
throw new ArgumentNullException("allPrograms");
}
- if (currentRecordings == null)
- {
- throw new ArgumentNullException("currentRecordings");
- }
// Exclude programs that have already ended
allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow && i.StartDate > DateTime.UtcNow);
allPrograms = GetProgramsForSeries(seriesTimer, allPrograms);
- var recordingShowIds = currentRecordings.Select(i => i.ProgramId).Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
-
- allPrograms = allPrograms.Where(i => !recordingShowIds.Contains(i.Id, StringComparer.OrdinalIgnoreCase));
+ if (filterByCurrentRecordings)
+ {
+ allPrograms = allPrograms.Where(i => !IsProgramAlreadyInLibrary(i));
+ }
return allPrograms.Select(i => RecordingHelper.CreateTimer(i, seriesTimer));
}
+ private bool IsProgramAlreadyInLibrary(ProgramInfo program)
+ {
+ if ((program.EpisodeNumber.HasValue && program.SeasonNumber.HasValue) || !string.IsNullOrWhiteSpace(program.EpisodeTitle))
+ {
+ var seriesIds = _libraryManager.GetItemIds(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Series).Name },
+ Name = program.Name
+
+ }).Select(i => i.ToString("N")).ToArray();
+
+ if (seriesIds.Length == 0)
+ {
+ return false;
+ }
+
+ if (program.EpisodeNumber.HasValue && program.SeasonNumber.HasValue)
+ {
+ var result = _libraryManager.GetItemsResult(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ ParentIndexNumber = program.SeasonNumber.Value,
+ IndexNumber = program.EpisodeNumber.Value,
+ AncestorIds = seriesIds,
+ ExcludeLocationTypes = new[] { LocationType.Virtual }
+ });
+
+ if (result.TotalRecordCount > 0)
+ {
+ return true;
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(program.EpisodeTitle))
+ {
+ var result = _libraryManager.GetItemsResult(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ Name = program.EpisodeTitle,
+ AncestorIds = seriesIds,
+ ExcludeLocationTypes = new[] { LocationType.Virtual }
+ });
+
+ if (result.TotalRecordCount > 0)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
private IEnumerable<ProgramInfo> GetProgramsForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms)
{
if (!seriesTimer.RecordAnyTime)
@@ -1132,6 +1265,47 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
});
}
+ public List<VirtualFolderInfo> GetRecordingFolders()
+ {
+ var list = new List<VirtualFolderInfo>();
+
+ var defaultFolder = RecordingPath;
+ var defaultName = "Recordings";
+
+ if (Directory.Exists(defaultFolder))
+ {
+ list.Add(new VirtualFolderInfo
+ {
+ Locations = new List<string> { defaultFolder },
+ Name = defaultName
+ });
+ }
+
+ var customPath = GetConfiguration().MovieRecordingPath;
+ if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath))
+ {
+ list.Add(new VirtualFolderInfo
+ {
+ Locations = new List<string> { customPath },
+ Name = "Recorded Movies",
+ CollectionType = CollectionType.Movies
+ });
+ }
+
+ customPath = GetConfiguration().SeriesRecordingPath;
+ if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath))
+ {
+ list.Add(new VirtualFolderInfo
+ {
+ Locations = new List<string> { customPath },
+ Name = "Recorded Series",
+ CollectionType = CollectionType.TvShows
+ });
+ }
+
+ return list;
+ }
+
class ActiveRecordingInfo
{
public string Path { get; set; }
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 442f151dd..e9ea49fa3 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
@@ -23,6 +24,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly IFileSystem _fileSystem;
private readonly IMediaEncoder _mediaEncoder;
private readonly IApplicationPaths _appPaths;
+ private readonly LiveTvOptions _liveTvOptions;
private bool _hasExited;
private Stream _logFileStream;
private string _targetPath;
@@ -30,17 +32,47 @@ 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)
+ public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions)
{
_logger = logger;
_fileSystem = fileSystem;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths;
_json = json;
+ _liveTvOptions = liveTvOptions;
+ }
+
+ 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)
+ {
+ // 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);
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ }
+
_targetPath = targetFile;
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
@@ -104,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var maxBitrate = 25000000;
videoArgs = string.Format(
- "-codec:v:0 libx264 -force_key_frames expr:gte(t,n_forced*5) {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync vfr -profile:v high -level 41",
+ "-codec:v:0 libx264 -force_key_frames expr:gte(t,n_forced*5) {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41",
GetOutputSizeParam(),
maxBitrate.ToString(CultureInfo.InvariantCulture));
}
@@ -129,7 +161,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var copyAudio = new[] { "aac", "mp3" };
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
- if (mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
+ if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase)))
{
return "-codec:a:0 copy";
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
index 268a4f751..5706b6ae9 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
@@ -17,5 +17,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
+
+ string GetOutputPath(MediaSourceInfo mediaSource, string targetFile);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index ab2b59d48..f85be5100 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -135,7 +135,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var channels = _libraryManager.GetItemList(new InternalItemsQuery
{
- IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }
+ IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
+ SortBy = new[] { ItemSortBy.SortName }
}).Cast<LiveTvChannel>();
@@ -164,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var val = query.IsFavorite.Value;
channels = channels
- .Where(i => _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite == val);
+ .Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val);
}
if (query.IsLiked.HasValue)
@@ -174,7 +175,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
channels = channels
.Where(i =>
{
- var likes = _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).Likes;
+ var likes = _userDataManager.GetUserData(user, i).Likes;
return likes.HasValue && likes.Value == val;
});
@@ -187,7 +188,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
channels = channels
.Where(i =>
{
- var likes = _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).Likes;
+ var likes = _userDataManager.GetUserData(user, i).Likes;
return likes.HasValue && likes.Value != val;
});
@@ -200,7 +201,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
if (enableFavoriteSorting)
{
- var userData = _userDataManager.GetUserData(user.Id, i.GetUserDataKey());
+ var userData = _userDataManager.GetUserData(user, i);
if (userData.IsFavorite)
{
@@ -886,7 +887,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
StartIndex = query.StartIndex,
Limit = query.Limit,
SortBy = query.SortBy,
- SortOrder = query.SortOrder ?? SortOrder.Ascending
+ SortOrder = query.SortOrder ?? SortOrder.Ascending,
+ EnableTotalRecordCount = query.EnableTotalRecordCount
};
if (query.HasAired.HasValue)
@@ -924,7 +926,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
IsAiring = query.IsAiring,
IsMovie = query.IsMovie,
IsSports = query.IsSports,
- IsKids = query.IsKids
+ IsKids = query.IsKids,
+ EnableTotalRecordCount = query.EnableTotalRecordCount
};
if (query.HasAired.HasValue)
@@ -1005,7 +1008,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var channel = GetInternalChannel(program.ChannelId);
- var channelUserdata = _userDataManager.GetUserData(userId, channel.GetUserDataKey());
+ var channelUserdata = _userDataManager.GetUserData(userId, channel);
if (channelUserdata.Likes ?? false)
{
@@ -1036,7 +1039,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (genres.TryGetValue(i, out genre))
{
- var genreUserdata = _userDataManager.GetUserData(userId, genre.GetUserDataKey());
+ var genreUserdata = _userDataManager.GetUserData(userId, genre);
if (genreUserdata.Likes ?? false)
{
@@ -1263,11 +1266,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private async Task CleanDatabaseInternal(List<Guid> currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
{
- var list = _itemRepo.GetItemIds(new InternalItemsQuery
+ var list = _itemRepo.GetItemIdsList(new InternalItemsQuery
{
IncludeItemTypes = validTypes
- }).Items.ToList();
+ }).ToList();
var numComplete = 0;
@@ -1513,6 +1516,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
dto.ChannelName = channel.Name;
dto.MediaType = channel.MediaType;
+ dto.ChannelNumber = channel.Number;
if (channel.HasImage(ImageType.Primary))
{
@@ -1852,6 +1856,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var channel = tuple.Item2;
dto.Number = channel.Number;
+ dto.ChannelNumber = channel.Number;
dto.ChannelType = channel.ChannelType;
dto.ServiceName = GetService(channel).Name;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 02a8d6938..9bb5b4fd7 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -224,7 +224,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
- //await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
+ if (EnableMediaProbing)
+ {
+ await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
+ }
+
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
}
catch (Exception ex)
@@ -239,6 +243,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
+ protected virtual bool EnableMediaProbing
+ {
+ get { return false; }
+ }
+
protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
try
@@ -268,6 +277,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
}
+ private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
+ {
+ await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
+
+ // Leave the resource locked. it will be released upstream
+ }
+ catch (Exception)
+ {
+ // Release the resource if there's some kind of failure.
+ resourcePool.Release();
+
+ throw;
+ }
+ }
+
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{
var originalRuntime = mediaSource.RunTimeTicks;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 469767c65..a3e5589e8 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -59,6 +59,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return id;
}
+ public string ApplyDuration(string streamPath, TimeSpan duration)
+ {
+ streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&";
+ streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture);
+
+ return streamPath;
+ }
+
private async Task<IEnumerable<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
{
var options = new HttpRequestOptions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 523f14dfc..2a974b545 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -134,7 +134,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
},
RequiresOpening = false,
- RequiresClosing = false
+ RequiresClosing = false,
+
+ ReadAtNativeFramerate = true
};
return new List<MediaSourceInfo> { mediaSource };
@@ -146,5 +148,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
return Task.FromResult(true);
}
+
+ public string ApplyDuration(string streamPath, TimeSpan duration)
+ {
+ return streamPath;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
index ffd85fd18..1e571c84f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
@@ -164,5 +164,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
return list;
}
+
+ public string ApplyDuration(string streamPath, TimeSpan duration)
+ {
+ return streamPath;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
index 0d5b5c4aa..5e2f98c09 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
@@ -1,178 +1,179 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
- "AppDeviceValues": "App: {0}, Device: {1}",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
- "FolderTypeMixed": "Mixed content",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV",
- "FolderTypeInherit": "Inherit",
- "HeaderCastCrew": "Cast & Crew",
- "HeaderPeople": "People",
- "ValueSpecialEpisodeName": "Special - {0}",
- "LabelChapterName": "Chapter {0}",
- "NameSeasonNumber": "Season {0}",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelGithub": "Github",
- "LabelApiDocumentation": "Api Documentation",
- "LabelDeveloperResources": "Developer Resources",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server",
- "CategorySync": "Sync",
- "CategoryUser": "User",
- "CategorySystem": "System",
- "CategoryApplication": "Application",
- "CategoryPlugin": "Plugin",
- "NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
- "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
- "NotificationOptionPluginInstalled": "Plugin installed",
- "NotificationOptionPluginUninstalled": "Plugin uninstalled",
- "NotificationOptionVideoPlayback": "Video playback started",
- "NotificationOptionAudioPlayback": "Audio playback started",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
- "NotificationOptionTaskFailed": "Scheduled task failure",
- "NotificationOptionInstallationFailed": "Installation failure",
- "NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionUserLockedOut": "User locked out",
- "NotificationOptionServerRestartRequired": "Server restart required",
- "ViewTypePlaylists": "Playlists",
- "ViewTypeMovies": "Movies",
- "ViewTypeTvShows": "TV",
- "ViewTypeGames": "Games",
- "ViewTypeMusic": "Music",
- "ViewTypeMusicGenres": "Genres",
- "ViewTypeMusicArtists": "Artists",
- "ViewTypeBoxSets": "Collections",
- "ViewTypeChannels": "Channels",
- "ViewTypeLiveTV": "Live TV",
- "ViewTypeLiveTvNowPlaying": "Now Airing",
- "ViewTypeLatestGames": "Latest Games",
- "ViewTypeRecentlyPlayedGames": "Recently Played",
- "ViewTypeGameFavorites": "Favorites",
- "ViewTypeGameSystems": "Game Systems",
- "ViewTypeGameGenres": "Genres",
- "ViewTypeTvResume": "Resume",
- "ViewTypeTvNextUp": "Next Up",
- "ViewTypeTvLatest": "Latest",
- "ViewTypeTvShowSeries": "Series",
- "ViewTypeTvGenres": "Genres",
- "ViewTypeTvFavoriteSeries": "Favorite Series",
- "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
- "ViewTypeMovieResume": "Resume",
- "ViewTypeMovieLatest": "Latest",
- "ViewTypeMovieMovies": "Movies",
- "ViewTypeMovieCollections": "Collections",
- "ViewTypeMovieFavorites": "Favorites",
- "ViewTypeMovieGenres": "Genres",
- "ViewTypeMusicLatest": "Latest",
- "ViewTypeMusicPlaylists": "Playlists",
- "ViewTypeMusicAlbums": "Albums",
- "ViewTypeMusicAlbumArtists": "Album Artists",
- "HeaderOtherDisplaySettings": "Display Settings",
- "ViewTypeMusicSongs": "Songs",
- "ViewTypeMusicFavorites": "Favorites",
- "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
- "ViewTypeMusicFavoriteArtists": "Favorite Artists",
- "ViewTypeMusicFavoriteSongs": "Favorite Songs",
- "ViewTypeFolders": "Folders",
- "ViewTypeLiveTvRecordingGroups": "Recordings",
- "ViewTypeLiveTvChannels": "Channels",
- "ScheduledTaskFailedWithName": "{0} failed",
- "LabelRunningTimeValue": "Running time: {0}",
- "ScheduledTaskStartedWithName": "{0} started",
- "VersionNumber": "Version {0}",
- "PluginInstalledWithName": "{0} was installed",
- "PluginUpdatedWithName": "{0} was updated",
- "PluginUninstalledWithName": "{0} was uninstalled",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
- "LabelIpAddressValue": "Ip address: {0}",
- "DeviceOnlineWithName": "{0} is connected",
- "UserOnlineFromDevice": "{0} is online from {1}",
- "ProviderValue": "Provider: {0}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
- "UserCreatedWithName": "User {0} has been created",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserDeletedWithName": "User {0} has been deleted",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageApplicationUpdated": "Emby Server has been updated",
- "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
- "DeviceOfflineWithName": "{0} has disconnected",
- "UserLockedOutWithName": "User {0} has been locked out",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
- "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
- "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
- "HeaderUnidentified": "Unidentified",
- "HeaderImagePrimary": "Primary",
- "HeaderImageBackdrop": "Backdrop",
- "HeaderImageLogo": "Logo",
- "HeaderUserPrimaryImage": "User Image",
- "HeaderOverview": "Overview",
- "HeaderShortOverview": "Short Overview",
- "HeaderType": "Type",
- "HeaderSeverity": "Severity",
- "HeaderUser": "User",
- "HeaderName": "Name",
- "HeaderDate": "Date",
- "HeaderPremiereDate": "Premiere Date",
- "HeaderDateAdded": "Date Added",
- "HeaderReleaseDate": "Release date",
- "HeaderRuntime": "Runtime",
- "HeaderPlayCount": "Play Count",
- "HeaderSeason": "Season",
- "HeaderSeasonNumber": "Season number",
- "HeaderSeries": "Series:",
- "HeaderNetwork": "Network",
- "HeaderYear": "Year:",
- "HeaderYears": "Years:",
- "HeaderParentalRating": "Parental Rating",
- "HeaderCommunityRating": "Community rating",
- "HeaderTrailers": "Trailers",
- "HeaderSpecials": "Specials",
- "HeaderGameSystems": "Game Systems",
- "HeaderPlayers": "Players:",
- "HeaderAlbumArtists": "Album Artists",
- "HeaderAlbums": "Albums",
- "HeaderDisc": "Disc",
- "HeaderTrack": "Track",
- "HeaderAudio": "Audio",
- "HeaderVideo": "Video",
- "HeaderEmbeddedImage": "Embedded image",
- "HeaderResolution": "Resolution",
- "HeaderSubtitles": "Subtitles",
- "HeaderGenres": "Genres",
- "HeaderCountries": "Countries",
- "HeaderStatus": "Status",
- "HeaderTracks": "Tracks",
- "HeaderMusicArtist": "Music artist",
- "HeaderLocked": "Locked",
- "HeaderStudios": "Studios",
- "HeaderActor": "Actors",
- "HeaderComposer": "Composers",
- "HeaderDirector": "Directors",
- "HeaderGuestStar": "Guest star",
- "HeaderProducer": "Producers",
- "HeaderWriter": "Writers",
- "HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings",
- "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
+ "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
+ "AppDeviceValues": "App: {0}, Device: {1}",
+ "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "FolderTypeMixed": "Mixed content",
+ "FolderTypeMovies": "Movies",
+ "FolderTypeMusic": "Music",
+ "FolderTypeAdultVideos": "Adult videos",
+ "FolderTypePhotos": "Photos",
+ "FolderTypeMusicVideos": "Music videos",
+ "FolderTypeHomeVideos": "Home videos",
+ "FolderTypeGames": "Games",
+ "FolderTypeBooks": "Books",
+ "FolderTypeTvShows": "TV",
+ "FolderTypeInherit": "Inherit",
+ "HeaderCastCrew": "Cast & Crew",
+ "HeaderPeople": "People",
+ "ValueSpecialEpisodeName": "Special - {0}",
+ "LabelChapterName": "Chapter {0}",
+ "NameSeasonUnknown": "Season Unknown",
+ "NameSeasonNumber": "Season {0}",
+ "LabelExit": "Exit",
+ "LabelVisitCommunity": "Visit Community",
+ "LabelGithub": "Github",
+ "LabelApiDocumentation": "Api Documentation",
+ "LabelDeveloperResources": "Developer Resources",
+ "LabelBrowseLibrary": "Browse Library",
+ "LabelConfigureServer": "Configure Emby",
+ "LabelRestartServer": "Restart Server",
+ "CategorySync": "Sync",
+ "CategoryUser": "User",
+ "CategorySystem": "System",
+ "CategoryApplication": "Application",
+ "CategoryPlugin": "Plugin",
+ "NotificationOptionPluginError": "Plugin failure",
+ "NotificationOptionApplicationUpdateAvailable": "Application update available",
+ "NotificationOptionApplicationUpdateInstalled": "Application update installed",
+ "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
+ "NotificationOptionPluginInstalled": "Plugin installed",
+ "NotificationOptionPluginUninstalled": "Plugin uninstalled",
+ "NotificationOptionVideoPlayback": "Video playback started",
+ "NotificationOptionAudioPlayback": "Audio playback started",
+ "NotificationOptionGamePlayback": "Game playback started",
+ "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
+ "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
+ "NotificationOptionGamePlaybackStopped": "Game playback stopped",
+ "NotificationOptionTaskFailed": "Scheduled task failure",
+ "NotificationOptionInstallationFailed": "Installation failure",
+ "NotificationOptionNewLibraryContent": "New content added",
+ "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
+ "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionUserLockedOut": "User locked out",
+ "NotificationOptionServerRestartRequired": "Server restart required",
+ "ViewTypePlaylists": "Playlists",
+ "ViewTypeMovies": "Movies",
+ "ViewTypeTvShows": "TV",
+ "ViewTypeGames": "Games",
+ "ViewTypeMusic": "Music",
+ "ViewTypeMusicGenres": "Genres",
+ "ViewTypeMusicArtists": "Artists",
+ "ViewTypeBoxSets": "Collections",
+ "ViewTypeChannels": "Channels",
+ "ViewTypeLiveTV": "Live TV",
+ "ViewTypeLiveTvNowPlaying": "Now Airing",
+ "ViewTypeLatestGames": "Latest Games",
+ "ViewTypeRecentlyPlayedGames": "Recently Played",
+ "ViewTypeGameFavorites": "Favorites",
+ "ViewTypeGameSystems": "Game Systems",
+ "ViewTypeGameGenres": "Genres",
+ "ViewTypeTvResume": "Resume",
+ "ViewTypeTvNextUp": "Next Up",
+ "ViewTypeTvLatest": "Latest",
+ "ViewTypeTvShowSeries": "Series",
+ "ViewTypeTvGenres": "Genres",
+ "ViewTypeTvFavoriteSeries": "Favorite Series",
+ "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
+ "ViewTypeMovieResume": "Resume",
+ "ViewTypeMovieLatest": "Latest",
+ "ViewTypeMovieMovies": "Movies",
+ "ViewTypeMovieCollections": "Collections",
+ "ViewTypeMovieFavorites": "Favorites",
+ "ViewTypeMovieGenres": "Genres",
+ "ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
+ "ViewTypeMusicAlbums": "Albums",
+ "ViewTypeMusicAlbumArtists": "Album Artists",
+ "HeaderOtherDisplaySettings": "Display Settings",
+ "ViewTypeMusicSongs": "Songs",
+ "ViewTypeMusicFavorites": "Favorites",
+ "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
+ "ViewTypeMusicFavoriteArtists": "Favorite Artists",
+ "ViewTypeMusicFavoriteSongs": "Favorite Songs",
+ "ViewTypeFolders": "Folders",
+ "ViewTypeLiveTvRecordingGroups": "Recordings",
+ "ViewTypeLiveTvChannels": "Channels",
+ "ScheduledTaskFailedWithName": "{0} failed",
+ "LabelRunningTimeValue": "Running time: {0}",
+ "ScheduledTaskStartedWithName": "{0} started",
+ "VersionNumber": "Version {0}",
+ "PluginInstalledWithName": "{0} was installed",
+ "PluginUpdatedWithName": "{0} was updated",
+ "PluginUninstalledWithName": "{0} was uninstalled",
+ "ItemAddedWithName": "{0} was added to the library",
+ "ItemRemovedWithName": "{0} was removed from the library",
+ "LabelIpAddressValue": "Ip address: {0}",
+ "DeviceOnlineWithName": "{0} is connected",
+ "UserOnlineFromDevice": "{0} is online from {1}",
+ "ProviderValue": "Provider: {0}",
+ "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
+ "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
+ "UserCreatedWithName": "User {0} has been created",
+ "UserPasswordChangedWithName": "Password has been changed for user {0}",
+ "UserDeletedWithName": "User {0} has been deleted",
+ "MessageServerConfigurationUpdated": "Server configuration has been updated",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
+ "MessageApplicationUpdated": "Emby Server has been updated",
+ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
+ "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
+ "DeviceOfflineWithName": "{0} has disconnected",
+ "UserLockedOutWithName": "User {0} has been locked out",
+ "UserOfflineFromDevice": "{0} has disconnected from {1}",
+ "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
+ "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+ "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
+ "HeaderUnidentified": "Unidentified",
+ "HeaderImagePrimary": "Primary",
+ "HeaderImageBackdrop": "Backdrop",
+ "HeaderImageLogo": "Logo",
+ "HeaderUserPrimaryImage": "User Image",
+ "HeaderOverview": "Overview",
+ "HeaderShortOverview": "Short Overview",
+ "HeaderType": "Type",
+ "HeaderSeverity": "Severity",
+ "HeaderUser": "User",
+ "HeaderName": "Name",
+ "HeaderDate": "Date",
+ "HeaderPremiereDate": "Premiere Date",
+ "HeaderDateAdded": "Date Added",
+ "HeaderReleaseDate": "Release date",
+ "HeaderRuntime": "Runtime",
+ "HeaderPlayCount": "Play Count",
+ "HeaderSeason": "Season",
+ "HeaderSeasonNumber": "Season number",
+ "HeaderSeries": "Series:",
+ "HeaderNetwork": "Network",
+ "HeaderYear": "Year:",
+ "HeaderYears": "Years:",
+ "HeaderParentalRating": "Parental Rating",
+ "HeaderCommunityRating": "Community rating",
+ "HeaderTrailers": "Trailers",
+ "HeaderSpecials": "Specials",
+ "HeaderGameSystems": "Game Systems",
+ "HeaderPlayers": "Players:",
+ "HeaderAlbumArtists": "Album Artists",
+ "HeaderAlbums": "Albums",
+ "HeaderDisc": "Disc",
+ "HeaderTrack": "Track",
+ "HeaderAudio": "Audio",
+ "HeaderVideo": "Video",
+ "HeaderEmbeddedImage": "Embedded image",
+ "HeaderResolution": "Resolution",
+ "HeaderSubtitles": "Subtitles",
+ "HeaderGenres": "Genres",
+ "HeaderCountries": "Countries",
+ "HeaderStatus": "Status",
+ "HeaderTracks": "Tracks",
+ "HeaderMusicArtist": "Music artist",
+ "HeaderLocked": "Locked",
+ "HeaderStudios": "Studios",
+ "HeaderActor": "Actors",
+ "HeaderComposer": "Composers",
+ "HeaderDirector": "Directors",
+ "HeaderGuestStar": "Guest star",
+ "HeaderProducer": "Producers",
+ "HeaderWriter": "Writers",
+ "HeaderParentalRatings": "Parental Ratings",
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 60d8f737f..aff3a5e16 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -68,15 +68,16 @@
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="SocketHttpListener, Version=1.0.5908.28560, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SocketHttpListener.1.0.0.29\lib\net45\SocketHttpListener.dll</HintPath>
+ <Reference Include="SimpleInjector, Version=3.1.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <HintPath>..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="SocketHttpListener, Version=1.0.5955.1537, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\SocketHttpListener.1.0.0.30\lib\net45\SocketHttpListener.dll</HintPath>
+ <Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
- <Reference Include="System.Data.SQLite">
- <HintPath>..\ThirdParty\System.Data.SQLite.ManagedOnly\1.0.94.0\System.Data.SQLite.dll</HintPath>
- </Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net" />
@@ -257,6 +258,8 @@
<Compile Include="Notifications\IConfigurableNotificationService.cs" />
<Compile Include="Persistence\BaseSqliteRepository.cs" />
<Compile Include="Persistence\CleanDatabaseScheduledTask.cs" />
+ <Compile Include="Persistence\DataExtensions.cs" />
+ <Compile Include="Persistence\IDbConnector.cs" />
<Compile Include="Persistence\MediaStreamColumns.cs" />
<Compile Include="Social\SharingManager.cs" />
<Compile Include="Social\SharingRepository.cs" />
@@ -271,7 +274,6 @@
<Compile Include="Notifications\InternalNotificationService.cs" />
<Compile Include="Notifications\NotificationConfigurationFactory.cs" />
<Compile Include="Notifications\NotificationManager.cs" />
- <Compile Include="Persistence\SqliteExtensions.cs" />
<Compile Include="Persistence\SqliteFileOrganizationRepository.cs" />
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
<Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
diff --git a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 7302431e1..cecf03ddf 100644
--- a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -32,11 +32,11 @@ namespace MediaBrowser.Server.Implementations.Notifications
_appPaths = appPaths;
}
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "notifications.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
index 031333f2c..2a2f9a09d 100644
--- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
@@ -110,6 +110,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
_config.SaveConfiguration();
}
+ if (_config.Configuration.SchemaVersion < SqliteItemRepository.LatestSchemaVersion)
+ {
+ _config.Configuration.SchemaVersion = SqliteItemRepository.LatestSchemaVersion;
+ _config.SaveConfiguration();
+ }
+
if (EnableUnavailableMessage)
{
EnableUnavailableMessage = false;
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs
index 4fb1e07dd..103b75f84 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/DataExtensions.cs
@@ -3,16 +3,12 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Data;
-using System.Data.SQLite;
using System.IO;
using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Persistence
{
- /// <summary>
- /// Class SQLiteExtensions
- /// </summary>
- static class SqliteExtensions
+ static class DataExtensions
{
/// <summary>
/// Determines whether the specified conn is open.
@@ -28,11 +24,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return (IDataParameter)cmd.Parameters[index];
}
-
+
public static IDataParameter Add(this IDataParameterCollection paramCollection, IDbCommand cmd, string name, DbType type)
{
var param = cmd.CreateParameter();
-
+
param.ParameterName = name;
param.DbType = type;
@@ -48,11 +44,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
param.ParameterName = name;
paramCollection.Add(param);
-
+
return param;
}
-
+
/// <summary>
/// Gets a stream from a DataReader at a given ordinal
/// </summary>
@@ -122,38 +118,6 @@ 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)
- {
- 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 static void Attach(IDbConnection db, string path, string alias)
{
using (var cmd = db.CreateCommand())
diff --git a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
new file mode 100644
index 000000000..cac9fe983
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs
@@ -0,0 +1,10 @@
+using System.Data;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+ public interface IDbConnector
+ {
+ Task<IDbConnection> Connect(string dbPath);
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
index debcd054f..76682c63b 100644
--- a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
@@ -26,6 +26,38 @@ namespace MediaBrowser.Server.Implementations.Persistence
AddCodecTagColumn();
AddCommentColumn();
AddNalColumn();
+ AddIsAvcColumn();
+ }
+
+ private void AddIsAvcColumn()
+ {
+ 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, "IsAvc", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column IsAvc BIT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
}
private void AddNalColumn()
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
index 45e0304c1..6077cfdba 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
@@ -52,11 +52,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
index 2d5aad04d..037776997 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
@@ -35,11 +35,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index fb655c9cb..308ca90e0 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -1,4 +1,3 @@
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@@ -18,7 +17,9 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.LiveTv;
@@ -54,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// <summary>
/// The _app paths
/// </summary>
- private readonly IApplicationPaths _appPaths;
+ private readonly IServerConfigurationManager _config;
/// <summary>
/// The _save item command
@@ -77,38 +78,33 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deleteAncestorsCommand;
private IDbCommand _saveAncestorCommand;
+ private IDbCommand _deleteUserDataKeysCommand;
+ private IDbCommand _saveUserDataKeysCommand;
+
private IDbCommand _updateInheritedRatingCommand;
private IDbCommand _updateInheritedTagsCommand;
- private const int LatestSchemaVersion = 63;
+ public const int LatestSchemaVersion = 78;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
/// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="logManager">The log manager.</param>
- /// <exception cref="System.ArgumentNullException">
- /// appPaths
- /// or
- /// jsonSerializer
- /// </exception>
- public SqliteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+ public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager)
: base(logManager)
{
- if (appPaths == null)
+ if (config == null)
{
- throw new ArgumentNullException("appPaths");
+ throw new ArgumentNullException("config");
}
if (jsonSerializer == null)
{
throw new ArgumentNullException("jsonSerializer");
}
- _appPaths = appPaths;
+ _config = config;
_jsonSerializer = jsonSerializer;
- _criticReviewsPath = Path.Combine(_appPaths.DataPath, "critic-reviews");
+ _criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews");
}
private const string ChaptersTableName = "Chapters2";
@@ -117,14 +113,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
- var dbFile = Path.Combine(_appPaths.DataPath, "library.db");
+ var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).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, 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, PRIMARY KEY (ItemId, StreamIndex))";
string[] queries = {
@@ -137,15 +133,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
"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 People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
"create index if not exists idxPeopleItemId on People(ItemId)",
"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+" on "+ChaptersTableName+"(ItemId, ChapterIndex)",
+ "create index if not exists idx_"+ChaptersTableName+"1 on "+ChaptersTableName+"(ItemId)",
createMediaStreamsTableCommand,
- "create index if not exists idx_mediastreams on mediastreams(ItemId, StreamIndex)",
+ "create index if not exists idx_mediastreams1 on mediastreams(ItemId)",
//pragmas
"pragma temp_store = memory",
@@ -226,22 +225,35 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "CriticRatingSummary", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "DateModifiedDuringLastRefresh", "DATETIME");
_connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text");
+ _connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME");
+ _connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text");
+
+ _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT");
+
+ string[] postQueries =
+ {
+ "create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)",
+ "create index if not exists idx_Type on TypedBaseItems(Type)"
+ };
+
+ _connection.RunQueries(postQueries, Logger);
PrepareStatements();
new MediaStreamColumns(_connection, Logger).AddColumns();
- var chapterDbFile = Path.Combine(_appPaths.DataPath, "chapters.db");
- if (File.Exists(chapterDbFile))
- {
- MigrateChapters(chapterDbFile);
- }
-
- var mediaStreamsDbFile = Path.Combine(_appPaths.DataPath, "mediainfo.db");
+ var mediaStreamsDbFile = Path.Combine(_config.ApplicationPaths.DataPath, "mediainfo.db");
if (File.Exists(mediaStreamsDbFile))
{
MigrateMediaStreams(mediaStreamsDbFile);
}
+
+ DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb");
}
private void MigrateMediaStreams(string file)
@@ -250,7 +262,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
var backupFile = file + ".bak";
File.Copy(file, backupFile, true);
- SqliteExtensions.Attach(_connection, backupFile, "MediaInfoOld");
+ DataExtensions.Attach(_connection, backupFile, "MediaInfoOld");
var columns = string.Join(",", _mediaStreamSaveColumns);
@@ -270,30 +282,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- private void MigrateChapters(string file)
- {
- try
- {
- var backupFile = file + ".bak";
- File.Copy(file, backupFile, true);
- SqliteExtensions.Attach(_connection, backupFile, "ChaptersOld");
-
- string[] queries = {
- "REPLACE INTO "+ChaptersTableName+"(ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) SELECT ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath FROM ChaptersOld.Chapters;"
- };
-
- _connection.RunQueries(queries, Logger);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error migrating chapter database", ex);
- }
- finally
- {
- TryDeleteFile(file);
- }
- }
-
private void TryDeleteFile(string file)
{
try
@@ -359,7 +347,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
"Tags",
"SourceType",
"TrailerTypes",
- "DateModifiedDuringLastRefresh"
+ "DateModifiedDuringLastRefresh",
+ "OriginalTitle",
+ "PrimaryVersionId",
+ "DateLastMediaAdded",
+ "Album",
+ "CriticRating",
+ "CriticRatingSummary"
};
private readonly string[] _mediaStreamSaveColumns =
@@ -391,7 +385,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
"RefFrames",
"CodecTag",
"Comment",
- "NalLengthSize"
+ "NalLengthSize",
+ "IsAvc"
};
/// <summary>
@@ -465,7 +460,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
"CriticRating",
"CriticRatingSummary",
"DateModifiedDuringLastRefresh",
- "InheritedTags"
+ "InheritedTags",
+ "CleanName",
+ "PresentationUniqueKey",
+ "SlugName",
+ "OriginalTitle",
+ "PrimaryVersionId",
+ "DateLastMediaAdded",
+ "Album"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -550,6 +552,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
_updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid";
_updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@Guid");
_updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@InheritedTags");
+
+ // user data
+ _deleteUserDataKeysCommand = _connection.CreateCommand();
+ _deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id";
+ _deleteUserDataKeysCommand.Parameters.Add(_deleteUserDataKeysCommand, "@Id");
+
+ _saveUserDataKeysCommand = _connection.CreateCommand();
+ _saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)";
+ _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@ItemId");
+ _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@UserDataKey");
+ _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@Priority");
+
}
/// <summary>
@@ -791,6 +805,41 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = null;
}
+ if (string.IsNullOrWhiteSpace(item.Name))
+ {
+ _saveItemCommand.GetParameter(index++).Value = null;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics();
+ }
+
+ _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey;
+ _saveItemCommand.GetParameter(index++).Value = item.SlugName;
+ _saveItemCommand.GetParameter(index++).Value = item.OriginalTitle;
+
+ var video = item as Video;
+ if (video != null)
+ {
+ _saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(index++).Value = null;
+ }
+
+ var folder = item as Folder;
+ if (folder != null && folder.DateLastMediaAdded.HasValue)
+ {
+ _saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(index++).Value = null;
+ }
+
+ _saveItemCommand.GetParameter(index++).Value = item.Album;
+
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@@ -799,6 +848,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction);
}
+
+ UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction);
}
transaction.Commit();
@@ -1168,6 +1219,41 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.DateModifiedDuringLastRefresh = reader.GetDateTime(51).ToUniversalTime();
}
+ if (!reader.IsDBNull(52))
+ {
+ item.OriginalTitle = reader.GetString(52);
+ }
+
+ var video = item as Video;
+ if (video != null)
+ {
+ if (!reader.IsDBNull(53))
+ {
+ video.PrimaryVersionId = reader.GetString(53);
+ }
+ }
+
+ var folder = item as Folder;
+ if (folder != null && !reader.IsDBNull(54))
+ {
+ folder.DateLastMediaAdded = reader.GetDateTime(54).ToUniversalTime();
+ }
+
+ if (!reader.IsDBNull(55))
+ {
+ item.Album = reader.GetString(55);
+ }
+
+ if (!reader.IsDBNull(56))
+ {
+ item.CriticRating = reader.GetFloat(56);
+ }
+
+ if (!reader.IsDBNull(57))
+ {
+ item.CriticRatingSummary = reader.GetString(57);
+ }
+
return item;
}
@@ -1225,6 +1311,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
throw new ArgumentNullException("id");
}
+ var list = new List<ChapterInfo>();
using (var cmd = _connection.CreateCommand())
{
@@ -1236,10 +1323,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
while (reader.Read())
{
- yield return GetChapter(reader);
+ list.Add(GetChapter(reader));
}
}
}
+
+ return list;
}
/// <summary>
@@ -1411,34 +1500,96 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- public IEnumerable<BaseItem> GetItemsOfType(Type type)
+ private bool EnableJoinUserData(InternalItemsQuery query)
{
- if (type == null)
+ if (_config.Configuration.SchemaVersion < 76)
{
- throw new ArgumentNullException("type");
+ return false;
}
- CheckDisposed();
+ if (query.User == null)
+ {
+ return false;
+ }
- using (var cmd = _connection.CreateCommand())
+ if (query.SortBy != null && query.SortBy.Length > 0)
+ {
+ if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ if (query.IsFavoriteOrLiked.HasValue)
{
- cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where type = @type";
+ return true;
+ }
- cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName;
+ if (query.IsFavorite.HasValue)
+ {
+ return true;
+ }
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (reader.Read())
- {
- var item = GetItem(reader);
+ if (query.IsResumable.HasValue)
+ {
+ return true;
+ }
- if (item != null)
- {
- yield return item;
- }
- }
- }
+ if (query.IsPlayed.HasValue)
+ {
+ return true;
}
+
+ if (query.IsLiked.HasValue)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
+ {
+ var list = startColumns.ToList();
+
+ if (EnableJoinUserData(query))
+ {
+ list.Add("UserDataDb.UserData.UserId");
+ list.Add("UserDataDb.UserData.lastPlayedDate");
+ list.Add("UserDataDb.UserData.playbackPositionTicks");
+ list.Add("UserDataDb.UserData.playcount");
+ list.Add("UserDataDb.UserData.isFavorite");
+ list.Add("UserDataDb.UserData.played");
+ list.Add("UserDataDb.UserData.rating");
+ }
+
+ return list.ToArray();
+ }
+
+ private string GetJoinUserDataText(InternalItemsQuery query)
+ {
+ if (!EnableJoinUserData(query))
+ {
+ return string.Empty;
+ }
+
+ return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key";
}
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
@@ -1450,11 +1601,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ var now = DateTime.UtcNow;
+
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems";
+ cmd.CommandText += GetJoinUserDataText(query);
- var whereClauses = GetWhereClauses(query, cmd, true);
+ if (EnableJoinUserData(query))
+ {
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id;
+ }
+
+ var whereClauses = GetWhereClauses(query, cmd);
var whereText = whereClauses.Count == 0 ?
string.Empty :
@@ -1462,17 +1621,31 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += " Group by PresentationUniqueKey";
+ }
+
cmd.CommandText += GetOrderByText(query);
- if (query.Limit.HasValue)
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
- }
+ var limit = query.Limit ?? int.MaxValue;
+
+ cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
- //Logger.Debug(cmd.CommandText);
+ if (query.StartIndex.HasValue)
+ {
+ cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
+ }
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
+ //Logger.Debug("GetItemList query time: {0}ms. Query: {1}",
+ // Convert.ToInt32((DateTime.UtcNow - now).TotalMilliseconds),
+ // cmd.CommandText);
+
while (reader.Read())
{
var item = GetItem(reader);
@@ -1494,40 +1667,70 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ var now = DateTime.UtcNow;
+
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems";
+ cmd.CommandText += GetJoinUserDataText(query);
+
+ if (EnableJoinUserData(query))
+ {
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id;
+ }
- var whereClauses = GetWhereClauses(query, cmd, false);
+ var whereClauses = GetWhereClauses(query, cmd);
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
- whereClauses = GetWhereClauses(query, cmd, true);
-
var whereText = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
cmd.CommandText += whereText;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += " Group by PresentationUniqueKey";
+ }
+
cmd.CommandText += GetOrderByText(query);
- if (query.Limit.HasValue)
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ var limit = query.Limit ?? int.MaxValue;
+
+ cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+
+ if (query.StartIndex.HasValue)
+ {
+ cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
}
- cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ }
+ else
+ {
+ cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ }
- //Logger.Debug(cmd.CommandText);
+ cmd.CommandText += GetJoinUserDataText(query);
+ cmd.CommandText += whereTextWithoutPaging;
var list = new List<BaseItem>();
var count = 0;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
+ //Logger.Debug("GetItems query time: {0}ms. Query: {1}",
+ // Convert.ToInt32((DateTime.UtcNow - now).TotalMilliseconds),
+ // cmd.CommandText);
+
while (reader.Read())
{
var item = GetItem(reader);
@@ -1558,28 +1761,68 @@ namespace MediaBrowser.Server.Implementations.Persistence
return string.Empty;
}
- var sortOrder = query.SortOrder == SortOrder.Descending ? "DESC" : "ASC";
+ var isAscending = query.SortOrder != SortOrder.Descending;
+
+ return " ORDER BY " + string.Join(",", query.SortBy.Select(i =>
+ {
+ var columnMap = MapOrderByField(i);
+ var columnAscending = isAscending;
+ if (columnMap.Item2)
+ {
+ columnAscending = !columnAscending;
+ }
+
+ var sortOrder = columnAscending ? "ASC" : "DESC";
- return " ORDER BY " + string.Join(",", query.SortBy.Select(i => MapOrderByField(i) + " " + sortOrder).ToArray());
+ return columnMap.Item1 + " " + sortOrder;
+ }).ToArray());
}
- private string MapOrderByField(string name)
+ private Tuple<string,bool> MapOrderByField(string name)
{
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
{
// TODO
- return "SortName";
+ return new Tuple<string, bool>("SortName", false);
}
if (string.Equals(name, ItemSortBy.Runtime, StringComparison.OrdinalIgnoreCase))
{
- return "RuntimeTicks";
+ return new Tuple<string, bool>("RuntimeTicks", false);
}
if (string.Equals(name, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
{
- return "RANDOM()";
+ return new Tuple<string, bool>("RANDOM()", false);
+ }
+ if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("LastPlayedDate", false);
+ }
+ if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("PlayCount", false);
+ }
+ if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("IsFavorite", true);
+ }
+ if (string.Equals(name, ItemSortBy.IsFolder, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("IsFolder", true);
+ }
+ if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("played", true);
+ }
+ if (string.Equals(name, ItemSortBy.IsUnplayed, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("played", false);
+ }
+ if (string.Equals(name, ItemSortBy.DateLastContentAdded, StringComparison.OrdinalIgnoreCase))
+ {
+ return new Tuple<string, bool>("DateLastMediaAdded", false);
}
- return name;
+ return new Tuple<string, bool>(name, false);
}
public List<Guid> GetItemIdsList(InternalItemsQuery query)
@@ -1591,11 +1834,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ var now = DateTime.UtcNow;
+
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select guid from TypedBaseItems";
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems";
+ cmd.CommandText += GetJoinUserDataText(query);
+
+ if (EnableJoinUserData(query))
+ {
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id;
+ }
- var whereClauses = GetWhereClauses(query, cmd, true);
+ var whereClauses = GetWhereClauses(query, cmd);
var whereText = whereClauses.Count == 0 ?
string.Empty :
@@ -1603,19 +1854,33 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += " Group by PresentationUniqueKey";
+ }
+
cmd.CommandText += GetOrderByText(query);
- if (query.Limit.HasValue)
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ var limit = query.Limit ?? int.MaxValue;
+
+ cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+
+ if (query.StartIndex.HasValue)
+ {
+ cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
}
var list = new List<Guid>();
- //Logger.Debug(cmd.CommandText);
-
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
+ //Logger.Debug("GetItemIdsList query time: {0}ms. Query: {1}",
+ // Convert.ToInt32((DateTime.UtcNow - now).TotalMilliseconds),
+ // cmd.CommandText);
+
while (reader.Read())
{
list.Add(reader.GetGuid(0));
@@ -1639,25 +1904,35 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cmd.CommandText = "select guid,path from TypedBaseItems";
- var whereClauses = GetWhereClauses(query, cmd, false);
+ var whereClauses = GetWhereClauses(query, cmd);
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
- whereClauses = GetWhereClauses(query, cmd, true);
-
var whereText = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
cmd.CommandText += whereText;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += " Group by PresentationUniqueKey";
+ }
+
cmd.CommandText += GetOrderByText(query);
- if (query.Limit.HasValue)
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ var limit = query.Limit ?? int.MaxValue;
+
+ cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+
+ if (query.StartIndex.HasValue)
+ {
+ cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
}
cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
@@ -1704,17 +1979,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
CheckDisposed();
+ var now = DateTime.UtcNow;
+
using (var cmd = _connection.CreateCommand())
{
- cmd.CommandText = "select guid from TypedBaseItems";
-
- var whereClauses = GetWhereClauses(query, cmd, false);
+ cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems";
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ var whereClauses = GetWhereClauses(query, cmd);
+ cmd.CommandText += GetJoinUserDataText(query);
- whereClauses = GetWhereClauses(query, cmd, true);
+ if (EnableJoinUserData(query))
+ {
+ cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id;
+ }
var whereText = whereClauses.Count == 0 ?
string.Empty :
@@ -1722,22 +1999,46 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.CommandText += whereText;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += " Group by PresentationUniqueKey";
+ }
+
cmd.CommandText += GetOrderByText(query);
- if (query.Limit.HasValue)
+ if (query.Limit.HasValue || query.StartIndex.HasValue)
{
- cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ var limit = query.Limit ?? int.MaxValue;
+
+ cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture);
+
+ if (query.StartIndex.HasValue)
+ {
+ cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
+ }
}
- cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+ if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66)
+ {
+ cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems";
+ }
+ else
+ {
+ cmd.CommandText += "; select count (guid) from TypedBaseItems";
+ }
+
+ cmd.CommandText += GetJoinUserDataText(query);
+ cmd.CommandText += whereText;
var list = new List<Guid>();
var count = 0;
- //Logger.Debug(cmd.CommandText);
-
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
+ //Logger.Debug("GetItemIds query time: {0}ms. Query: {1}",
+ // Convert.ToInt32((DateTime.UtcNow - now).TotalMilliseconds),
+ // cmd.CommandText);
+
while (reader.Read())
{
list.Add(reader.GetGuid(0));
@@ -1757,10 +2058,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- private List<string> GetWhereClauses(InternalItemsQuery query, IDbCommand cmd, bool addPaging)
+ private List<string> GetWhereClauses(InternalItemsQuery query, IDbCommand cmd)
{
var whereClauses = new List<string>();
+ if (EnableJoinUserData(query))
+ {
+ whereClauses.Add("(UserId is null or UserId=@UserId)");
+ }
if (query.IsCurrentSchema.HasValue)
{
if (query.IsCurrentSchema.Value)
@@ -1856,6 +2161,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.Parameters.Add(cmd, "@Path", DbType.String).Value = query.Path;
}
+ if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
+ {
+ whereClauses.Add("PresentationUniqueKey=@PresentationUniqueKey");
+ cmd.Parameters.Add(cmd, "@PresentationUniqueKey", DbType.String).Value = query.PresentationUniqueKey;
+ }
+
if (query.MinCommunityRating.HasValue)
{
whereClauses.Add("CommunityRating>=@MinCommunityRating");
@@ -1880,9 +2191,14 @@ namespace MediaBrowser.Server.Implementations.Persistence
// cmd.Parameters.Add(cmd, "@MaxPlayers", DbType.Int32).Value = query.MaxPlayers.Value;
//}
+ if (query.IndexNumber.HasValue)
+ {
+ whereClauses.Add("IndexNumber=@IndexNumber");
+ cmd.Parameters.Add(cmd, "@IndexNumber", DbType.Int32).Value = query.IndexNumber.Value;
+ }
if (query.ParentIndexNumber.HasValue)
{
- whereClauses.Add("ParentIndexNumber=@MinEndDate");
+ whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
cmd.Parameters.Add(cmd, "@ParentIndexNumber", DbType.Int32).Value = query.ParentIndexNumber.Value;
}
if (query.MinEndDate.HasValue)
@@ -1956,20 +2272,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add(clause);
}
- if (query.ExcludeTrailerTypes.Length > 0)
- {
- var clauses = new List<string>();
- var index = 0;
- foreach (var type in query.ExcludeTrailerTypes)
- {
- clauses.Add("(TrailerTypes is null OR TrailerTypes not like @TrailerTypes" + index + ")");
- cmd.Parameters.Add(cmd, "@TrailerTypes" + index, DbType.String).Value = "%" + type + "%";
- index++;
- }
- var clause = "(" + string.Join(" AND ", clauses.ToArray()) + ")";
- whereClauses.Add(clause);
- }
-
if (query.IsAiring.HasValue)
{
if (query.IsAiring.Value)
@@ -1993,10 +2295,126 @@ namespace MediaBrowser.Server.Implementations.Persistence
cmd.Parameters.Add(cmd, "@PersonName", DbType.String).Value = query.Person;
}
+ if (!string.IsNullOrWhiteSpace(query.SlugName))
+ {
+ if (_config.Configuration.SchemaVersion >= 70)
+ {
+ whereClauses.Add("SlugName=@SlugName");
+ }
+ else
+ {
+ whereClauses.Add("Name=@SlugName");
+ }
+ cmd.Parameters.Add(cmd, "@SlugName", DbType.String).Value = query.SlugName;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.Name))
+ {
+ if (_config.Configuration.SchemaVersion >= 66)
+ {
+ whereClauses.Add("CleanName=@Name");
+ cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name.RemoveDiacritics();
+ }
+ else
+ {
+ whereClauses.Add("Name=@Name");
+ cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name;
+ }
+ }
+
if (!string.IsNullOrWhiteSpace(query.NameContains))
{
- whereClauses.Add("Name like @NameContains");
- cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains + "%";
+ if (_config.Configuration.SchemaVersion >= 66)
+ {
+ whereClauses.Add("CleanName like @NameContains");
+ }
+ else
+ {
+ whereClauses.Add("Name like @NameContains");
+ }
+ cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains.RemoveDiacritics() + "%";
+ }
+ if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
+ {
+ whereClauses.Add("SortName like @NameStartsWith");
+ cmd.Parameters.Add(cmd, "@NameStartsWith", DbType.String).Value = query.NameStartsWith + "%";
+ }
+ if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater))
+ {
+ whereClauses.Add("SortName >= @NameStartsWithOrGreater");
+ // lowercase this because SortName is stored as lowercase
+ cmd.Parameters.Add(cmd, "@NameStartsWithOrGreater", DbType.String).Value = query.NameStartsWithOrGreater.ToLower();
+ }
+ if (!string.IsNullOrWhiteSpace(query.NameLessThan))
+ {
+ whereClauses.Add("SortName < @NameLessThan");
+ // lowercase this because SortName is stored as lowercase
+ cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower();
+ }
+
+ if (query.IsLiked.HasValue)
+ {
+ if (query.IsLiked.Value)
+ {
+ whereClauses.Add("rating>=@UserRating");
+ cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
+ }
+ else
+ {
+ whereClauses.Add("(rating is null or rating<@UserRating)");
+ cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue;
+ }
+ }
+
+ if (query.IsFavoriteOrLiked.HasValue)
+ {
+ if (query.IsFavoriteOrLiked.Value)
+ {
+ whereClauses.Add("IsFavorite=@IsFavoriteOrLiked");
+ }
+ else
+ {
+ whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavoriteOrLiked)");
+ }
+ cmd.Parameters.Add(cmd, "@IsFavoriteOrLiked", DbType.Boolean).Value = query.IsFavoriteOrLiked.Value;
+ }
+
+ if (query.IsFavorite.HasValue)
+ {
+ if (query.IsFavorite.Value)
+ {
+ whereClauses.Add("IsFavorite=@IsFavorite");
+ }
+ else
+ {
+ whereClauses.Add("(IsFavorite is null or IsFavorite=@IsFavorite)");
+ }
+ cmd.Parameters.Add(cmd, "@IsFavorite", DbType.Boolean).Value = query.IsFavorite.Value;
+ }
+
+ if (query.IsPlayed.HasValue)
+ {
+ if (query.IsPlayed.Value)
+ {
+ whereClauses.Add("(played=@IsPlayed)");
+ }
+ else
+ {
+ whereClauses.Add("(played is null or played=@IsPlayed)");
+ }
+ cmd.Parameters.Add(cmd, "@IsPlayed", DbType.Boolean).Value = query.IsPlayed.Value;
+ }
+
+ if (query.IsResumable.HasValue)
+ {
+ if (query.IsResumable.Value)
+ {
+ whereClauses.Add("playbackPositionTicks > 0");
+ }
+ else
+ {
+ whereClauses.Add("(playbackPositionTicks is null or playbackPositionTicks = 0)");
+ }
}
if (query.Genres.Length > 0)
@@ -2122,7 +2540,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (query.MediaTypes.Length == 1)
{
whereClauses.Add("MediaType=@MediaTypes");
- cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0].ToString();
+ cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0];
}
if (query.MediaTypes.Length > 1)
{
@@ -2131,7 +2549,28 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("MediaType in (" + val + ")");
}
- var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0;
+ if (query.AlbumNames.Length > 0)
+ {
+ var clause = "(";
+
+ var index = 0;
+ foreach (var name in query.AlbumNames)
+ {
+ if (index > 0)
+ {
+ clause += " OR ";
+ }
+ clause += "Album=@AlbumName" + index;
+ index++;
+ cmd.Parameters.Add(cmd, "@AlbumName" + index, DbType.String).Value = name;
+ }
+
+ clause += ")";
+ whereClauses.Add(clause);
+ }
+
+ //var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0;
+ var enableItemsByName = query.IncludeItemsByName ?? false;
if (query.TopParentIds.Length == 1)
{
@@ -2171,6 +2610,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + new Guid(i).ToString("N") + "'").ToArray());
whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause));
}
+ if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
+ {
+ var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey";
+ whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause));
+ cmd.Parameters.Add(cmd, "@AncestorWithPresentationUniqueKey", DbType.String).Value = query.AncestorWithPresentationUniqueKey;
+ }
if (query.BlockUnratedItems.Length == 1)
{
@@ -2194,28 +2639,50 @@ namespace MediaBrowser.Server.Implementations.Persistence
excludeTagIndex = 0;
foreach (var excludeTag in query.ExcludeInheritedTags)
{
- whereClauses.Add("(InheritedTags is null OR InheritedTags not like @excludeInheritedTag" + excludeTagIndex +")");
+ whereClauses.Add("(InheritedTags is null OR InheritedTags not like @excludeInheritedTag" + excludeTagIndex + ")");
cmd.Parameters.Add(cmd, "@excludeInheritedTag" + excludeTagIndex, DbType.String).Value = "%" + excludeTag + "%";
excludeTagIndex++;
}
- if (addPaging)
+ return whereClauses;
+ }
+
+ private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
+ {
+ if (!query.GroupByPresentationUniqueKey)
{
- if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ return false;
+ }
- var orderBy = GetOrderByText(query);
+ if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
+ {
+ return false;
+ }
- whereClauses.Add(string.Format("guid NOT IN (SELECT guid FROM TypedBaseItems {0}" + orderBy + " LIMIT {1})",
- pagingWhereText,
- query.StartIndex.Value.ToString(CultureInfo.InvariantCulture)));
- }
+ if (query.User == null)
+ {
+ return false;
}
- return whereClauses;
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new[] {
+ typeof(Episode).Name,
+ typeof(Video).Name ,
+ typeof(Movie).Name ,
+ typeof(MusicVideo).Name ,
+ typeof(Series).Name ,
+ typeof(Season).Name };
+
+ if (types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase)))
+ {
+ return true;
+ }
+
+ return false;
}
private static readonly Type[] KnownTypes =
@@ -2296,7 +2763,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
try
{
transaction = _connection.BeginTransaction();
-
+
foreach (var item in newValues)
{
_updateInheritedTagsCommand.GetParameter(0).Value = item.Item1;
@@ -2482,6 +2949,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteAncestorsCommand.Transaction = transaction;
_deleteAncestorsCommand.ExecuteNonQuery();
+ // Delete user data keys
+ _deleteUserDataKeysCommand.GetParameter(0).Value = id;
+ _deleteUserDataKeysCommand.Transaction = transaction;
+ _deleteUserDataKeysCommand.ExecuteNonQuery();
+
// Delete the item
_deleteItemCommand.GetParameter(0).Value = id;
_deleteItemCommand.Transaction = transaction;
@@ -2674,6 +3146,39 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ private void UpdateUserDataKeys(Guid itemId, List<string> keys, IDbTransaction transaction)
+ {
+ if (itemId == Guid.Empty)
+ {
+ throw new ArgumentNullException("itemId");
+ }
+
+ if (keys == null)
+ {
+ throw new ArgumentNullException("keys");
+ }
+
+ CheckDisposed();
+
+ // First delete
+ _deleteUserDataKeysCommand.GetParameter(0).Value = itemId;
+ _deleteUserDataKeysCommand.Transaction = transaction;
+
+ _deleteUserDataKeysCommand.ExecuteNonQuery();
+ var index = 0;
+
+ foreach (var key in keys)
+ {
+ _saveUserDataKeysCommand.GetParameter(0).Value = itemId;
+ _saveUserDataKeysCommand.GetParameter(1).Value = key;
+ _saveUserDataKeysCommand.GetParameter(2).Value = index;
+ index++;
+ _saveUserDataKeysCommand.Transaction = transaction;
+
+ _saveUserDataKeysCommand.ExecuteNonQuery();
+ }
+ }
+
public async Task UpdatePeople(Guid itemId, List<PersonInfo> people)
{
if (itemId == Guid.Empty)
@@ -2790,6 +3295,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
throw new ArgumentNullException("query");
}
+ var list = new List<MediaStream>();
+
using (var cmd = _connection.CreateCommand())
{
var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where";
@@ -2817,10 +3324,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
while (reader.Read())
{
- yield return GetMediaStream(reader);
+ list.Add(GetMediaStream(reader));
}
}
}
+
+ return list;
}
public async Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
@@ -2893,6 +3402,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStreamCommand.GetParameter(index++).Value = stream.CodecTag;
_saveStreamCommand.GetParameter(index++).Value = stream.Comment;
_saveStreamCommand.GetParameter(index++).Value = stream.NalLengthSize;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsAVC;
_saveStreamCommand.Transaction = transaction;
_saveStreamCommand.ExecuteNonQuery();
@@ -3056,6 +3566,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
item.NalLengthSize = reader.GetString(27);
}
+ if (!reader.IsDBNull(28))
+ {
+ item.IsAVC = reader.GetBoolean(28);
+ }
+
return item;
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
index dbceda727..40d5c9586 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
@@ -39,11 +39,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
index 63c41c71f..7f3b32e06 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
@@ -37,16 +37,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
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 index if not exists idx_userdata on userdata(key)",
"create unique index if not exists userdataindex on userdata (key, userId)",
//pragmas
@@ -295,11 +296,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- return new UserItemData
- {
- UserId = userId,
- Key = key
- };
+ return null;
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
index 9bd7e47f3..f7ca39a54 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
@@ -43,12 +43,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
-
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
+
string[] queries = {
"create table if not exists users (guid GUID primary key, data BLOB)",
diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
index 4a69646f8..ea2460719 100644
--- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
@@ -17,7 +17,7 @@ using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Server.Implementations.Photos
{
- public abstract class BaseDynamicImageProvider<T> : IHasChangeMonitor, IForcedProvider, ICustomMetadataProvider<T>, IHasOrder
+ public abstract class BaseDynamicImageProvider<T> : IHasItemChangeMonitor, IForcedProvider, ICustomMetadataProvider<T>, IHasOrder
where T : IHasMetadata
{
protected IFileSystem FileSystem { get; private set; }
@@ -109,6 +109,21 @@ namespace MediaBrowser.Server.Implementations.Photos
protected async Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
+ var image = item.GetImageInfo(imageType, 0);
+
+ if (image != null)
+ {
+ if (!image.IsLocalFile)
+ {
+ return ItemUpdateType.None;
+ }
+
+ if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
+ {
+ return ItemUpdateType.None;
+ }
+ }
+
var items = await GetItemsWithImages(item).ConfigureAwait(false);
return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
@@ -247,7 +262,7 @@ namespace MediaBrowser.Server.Implementations.Photos
get { return 7; }
}
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryServicee)
{
if (!Supports(item))
{
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
index 06ef05951..53c03b91c 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
@@ -158,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
return path;
}
- private IEnumerable<BaseItem> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user)
+ private Task<IEnumerable<BaseItem>> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user)
{
var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null);
@@ -183,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
var list = new List<LinkedChild>();
- var items = GetPlaylistItems(itemIds, playlist.MediaType, user)
+ var items = (await GetPlaylistItems(itemIds, playlist.MediaType, user).ConfigureAwait(false))
.Where(i => i.SupportsAddingToPlaylist)
.ToList();
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index e50de7bac..607a043a6 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -12,6 +12,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
@@ -85,8 +86,13 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <returns>Task.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
- var videos = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Video)
- .Cast<Video>()
+ var videos = _libraryManager.GetItemList(new InternalItemsQuery
+ {
+ MediaTypes = new[] { MediaType.Video },
+ IsFolder = false,
+ Recursive = true
+ })
+ .OfType<Video>()
.ToList();
var numComplete = 0;
@@ -97,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
try
{
- previouslyFailedImages = _fileSystem.ReadAllText(failHistoryPath)
+ previouslyFailedImages = _fileSystem.ReadAllText(failHistoryPath)
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.ToList();
}
diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
index b932f0cac..e8d9814ec 100644
--- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
@@ -27,11 +27,11 @@ namespace MediaBrowser.Server.Implementations.Security
_appPaths = appPaths;
}
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "authentication.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
index 8719f5448..33d106916 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
@@ -71,6 +71,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <value>The web socket listeners.</value>
private readonly List<IWebSocketListener> _webSocketListeners = new List<IWebSocketListener>();
+ private bool _disposed;
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerManager" /> class.
/// </summary>
@@ -143,6 +145,11 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <param name="e">The <see cref="WebSocketConnectEventArgs" /> instance containing the event data.</param>
void HttpServer_WebSocketConnected(object sender, WebSocketConnectEventArgs e)
{
+ if (_disposed)
+ {
+ return;
+ }
+
var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
{
OnReceive = ProcessWebSocketMessageReceived,
@@ -164,6 +171,11 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <param name="result">The result.</param>
private async void ProcessWebSocketMessageReceived(WebSocketMessageInfo result)
{
+ if (_disposed)
+ {
+ return;
+ }
+
//_logger.Debug("Websocket message received: {0}", result.MessageType);
var tasks = _webSocketListeners.Select(i => Task.Run(async () =>
@@ -244,6 +256,11 @@ namespace MediaBrowser.Server.Implementations.ServerManager
throw new ArgumentNullException("dataFunction");
}
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(GetType().Name);
+ }
+
cancellationToken.ThrowIfCancellationRequested();
var connectionsList = connections.Where(s => s.State == WebSocketState.Open).ToList();
@@ -301,6 +318,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// </summary>
public void Dispose()
{
+ _disposed = true;
+
Dispose(true);
GC.SuppressFinalize(this);
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 88f11c368..77843ef6b 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -601,11 +601,9 @@ namespace MediaBrowser.Server.Implementations.Session
if (libraryItem != null)
{
- var key = libraryItem.GetUserDataKey();
-
foreach (var user in users)
{
- await OnPlaybackStart(user.Id, key, libraryItem).ConfigureAwait(false);
+ await OnPlaybackStart(user.Id, libraryItem).ConfigureAwait(false);
}
}
@@ -632,12 +630,11 @@ namespace MediaBrowser.Server.Implementations.Session
/// Called when [playback start].
/// </summary>
/// <param name="userId">The user identifier.</param>
- /// <param name="userDataKey">The user data key.</param>
/// <param name="item">The item.</param>
/// <returns>Task.</returns>
- private async Task OnPlaybackStart(Guid userId, string userDataKey, IHasUserData item)
+ private async Task OnPlaybackStart(Guid userId, IHasUserData item)
{
- var data = _userDataRepository.GetUserData(userId, userDataKey);
+ var data = _userDataRepository.GetUserData(userId, item);
data.PlayCount++;
data.LastPlayedDate = DateTime.UtcNow;
@@ -676,11 +673,9 @@ namespace MediaBrowser.Server.Implementations.Session
if (libraryItem != null)
{
- var key = libraryItem.GetUserDataKey();
-
foreach (var user in users)
{
- await OnPlaybackProgress(user, key, libraryItem, info).ConfigureAwait(false);
+ await OnPlaybackProgress(user, libraryItem, info).ConfigureAwait(false);
}
}
@@ -714,9 +709,9 @@ namespace MediaBrowser.Server.Implementations.Session
StartIdleCheckTimer();
}
- private async Task OnPlaybackProgress(User user, string userDataKey, BaseItem item, PlaybackProgressInfo info)
+ private async Task OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
{
- var data = _userDataRepository.GetUserData(user.Id, userDataKey);
+ var data = _userDataRepository.GetUserData(user.Id, item);
var positionTicks = info.PositionTicks;
@@ -811,11 +806,9 @@ namespace MediaBrowser.Server.Implementations.Session
if (libraryItem != null)
{
- var key = libraryItem.GetUserDataKey();
-
foreach (var user in users)
{
- playedToCompletion = await OnPlaybackStopped(user.Id, key, libraryItem, info.PositionTicks, info.Failed).ConfigureAwait(false);
+ playedToCompletion = await OnPlaybackStopped(user.Id, libraryItem, info.PositionTicks, info.Failed).ConfigureAwait(false);
}
}
@@ -848,14 +841,14 @@ namespace MediaBrowser.Server.Implementations.Session
await SendPlaybackStoppedNotification(session, CancellationToken.None).ConfigureAwait(false);
}
- private async Task<bool> OnPlaybackStopped(Guid userId, string userDataKey, BaseItem item, long? positionTicks, bool playbackFailed)
+ private async Task<bool> OnPlaybackStopped(Guid userId, BaseItem item, long? positionTicks, bool playbackFailed)
{
bool playedToCompletion = false;
if (!playbackFailed)
{
- var data = _userDataRepository.GetUserData(userId, userDataKey);
-
+ var data = _userDataRepository.GetUserData(userId, item);
+
if (positionTicks.HasValue)
{
playedToCompletion = _userDataRepository.UpdatePlayState(item, data, positionTicks.Value);
@@ -1033,11 +1026,11 @@ namespace MediaBrowser.Server.Implementations.Session
if (byName != null)
{
- var itemFilter = byName.GetItemFilter();
-
- var items = user == null ?
- _libraryManager.RootFolder.GetRecursiveChildren(i => !i.IsFolder && itemFilter(i)) :
- user.RootFolder.GetRecursiveChildren(user, i => !i.IsFolder && itemFilter(i));
+ var items = byName.GetTaggedItems(new InternalItemsQuery(user)
+ {
+ IsFolder = false,
+ Recursive = true
+ });
return FilterToSingleMediaType(items)
.OrderBy(i => i.SortName);
@@ -1047,9 +1040,12 @@ namespace MediaBrowser.Server.Implementations.Session
{
var folder = (Folder)item;
- var items = user == null ?
- folder.GetRecursiveChildren(i => !i.IsFolder) :
- folder.GetRecursiveChildren(user, i => !i.IsFolder);
+ var items = folder.GetItems(new InternalItemsQuery(user)
+ {
+ Recursive = true,
+ IsFolder = false
+
+ }).Result.Items;
return FilterToSingleMediaType(items)
.OrderBy(i => i.SortName);
@@ -1374,8 +1370,8 @@ namespace MediaBrowser.Server.Implementations.Session
ServerId = _appHost.SystemId
};
}
-
-
+
+
private async Task<string> GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
diff --git a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
index d6d7f021a..317743eb1 100644
--- a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
+++ b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs
@@ -26,11 +26,11 @@ namespace MediaBrowser.Server.Implementations.Social
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "shares.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false);
string[] queries = {
diff --git a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
index 70cf805cf..91abbe34c 100644
--- a/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
@@ -49,8 +49,8 @@ namespace MediaBrowser.Server.Implementations.Sorting
private int Compare(Episode x, Episode y)
{
- var isXSpecial = (x.PhysicalSeasonNumber ?? -1) == 0;
- var isYSpecial = (y.PhysicalSeasonNumber ?? -1) == 0;
+ var isXSpecial = (x.ParentIndexNumber ?? -1) == 0;
+ var isYSpecial = (y.ParentIndexNumber ?? -1) == 0;
if (isXSpecial && isYSpecial)
{
@@ -74,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
{
// http://thetvdb.com/wiki/index.php?title=Special_Episodes
- var xSeason = x.PhysicalSeasonNumber ?? -1;
+ var xSeason = x.ParentIndexNumber ?? -1;
var ySeason = y.AirsAfterSeasonNumber ?? y.AirsBeforeSeasonNumber ?? -1;
if (xSeason != ySeason)
@@ -142,8 +142,8 @@ namespace MediaBrowser.Server.Implementations.Sorting
private int CompareEpisodes(Episode x, Episode y)
{
- var xValue = (x.PhysicalSeasonNumber ?? -1) * 1000 + (x.IndexNumber ?? -1);
- var yValue = (y.PhysicalSeasonNumber ?? -1) * 1000 + (y.IndexNumber ?? -1);
+ var xValue = (x.ParentIndexNumber ?? -1) * 1000 + (x.IndexNumber ?? -1);
+ var yValue = (y.ParentIndexNumber ?? -1) * 1000 + (y.IndexNumber ?? -1);
return xValue.CompareTo(yValue);
}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
index 68cd44ec9..e8c78b8e7 100644
--- a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
@@ -49,13 +49,13 @@ namespace MediaBrowser.Server.Implementations.Sorting
if (folder != null)
{
- return folder.GetRecursiveChildren(User, i => !i.IsFolder)
- .Select(i => i.DateCreated)
- .OrderByDescending(i => i)
- .FirstOrDefault();
+ if (folder.DateLastMediaAdded.HasValue)
+ {
+ return folder.DateLastMediaAdded.Value;
+ }
}
- return x.DateCreated;
+ return DateTime.MinValue;
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
index c881591be..3edf23020 100644
--- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
private DateTime GetDate(BaseItem x)
{
- var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(User, x);
if (userdata != null && userdata.LastPlayedDate.HasValue)
{
diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
index 1bc5261b4..8b14efffc 100644
--- a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
- var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey());
+ var userdata = UserDataRepository.GetUserData(User, x);
return userdata == null ? 0 : userdata.PlayCount;
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 33874b4d4..bbba06870 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -149,6 +149,11 @@ namespace MediaBrowser.Server.Implementations.Sync
{
var job = _syncRepo.GetJob(id);
+ if (job == null)
+ {
+ return Task.FromResult(true);
+ }
+
var result = _syncManager.GetJobItems(new SyncJobItemQuery
{
JobId = job.Id,
@@ -321,32 +326,27 @@ namespace MediaBrowser.Server.Implementations.Sync
var itemByName = item as IItemByName;
if (itemByName != null)
{
- var itemByNameFilter = itemByName.GetItemFilter();
-
- return user.RootFolder
- .GetRecursiveChildren(user, i => !i.IsFolder && itemByNameFilter(i));
- }
-
- var series = item as Series;
- if (series != null)
- {
- return series.GetEpisodes(user, false, false);
- }
-
- var season = item as Season;
- if (season != null)
- {
- return season.GetEpisodes(user, false, false);
+ return itemByName.GetTaggedItems(new InternalItemsQuery(user)
+ {
+ IsFolder = false,
+ Recursive = true
+ });
}
if (item.IsFolder)
{
var folder = (Folder)item;
- var items = folder.GetRecursiveChildren(user, i => !i.IsFolder);
+ var items = folder.GetItems(new InternalItemsQuery(user)
+ {
+ Recursive = true,
+ IsFolder = false
+
+ }).Result.Items;
if (!folder.IsPreSorted)
{
- items = items.OrderBy(i => i.SortName);
+ items = _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
+ .ToArray();
}
return items;
@@ -577,7 +577,7 @@ namespace MediaBrowser.Server.Implementations.Sync
conversionOptions.ItemId = item.Id.ToString("N");
conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
- var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions);
+ var streamInfo = new StreamBuilder(_mediaEncoder, _logger).BuildVideoItem(conversionOptions);
var mediaSource = streamInfo.MediaSource;
// No sense creating external subs if we're already burning one into the video
@@ -632,6 +632,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}, innerProgress, cancellationToken);
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
_syncManager.OnConversionComplete(jobItem);
}
catch (OperationCanceledException)
@@ -668,6 +669,7 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol));
}
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
jobItem.MediaSource = mediaSource;
}
@@ -779,7 +781,7 @@ namespace MediaBrowser.Server.Implementations.Sync
conversionOptions.ItemId = item.Id.ToString("N");
conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
- var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions);
+ var streamInfo = new StreamBuilder(_mediaEncoder, _logger).BuildAudioItem(conversionOptions);
var mediaSource = streamInfo.MediaSource;
jobItem.MediaSourceId = streamInfo.MediaSourceId;
@@ -819,6 +821,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}, innerProgress, cancellationToken);
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
_syncManager.OnConversionComplete(jobItem);
}
catch (OperationCanceledException)
@@ -855,6 +858,7 @@ namespace MediaBrowser.Server.Implementations.Sync
throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol));
}
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
jobItem.MediaSource = mediaSource;
}
@@ -871,6 +875,7 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.Progress = 50;
jobItem.Status = SyncJobItemStatus.ReadyToTransfer;
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
}
@@ -880,6 +885,7 @@ namespace MediaBrowser.Server.Implementations.Sync
jobItem.Progress = 50;
jobItem.Status = SyncJobItemStatus.ReadyToTransfer;
+ jobItem.ItemDateModifiedTicks = item.DateModified.Ticks;
await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index 044c8b93a..38edc3024 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -687,7 +687,7 @@ namespace MediaBrowser.Server.Implementations.Sync
private Task ReportOfflinePlayedItem(UserAction action)
{
var item = _libraryManager.GetItemById(action.ItemId);
- var userData = _userDataManager.GetUserData(new Guid(action.UserId), item.GetUserDataKey());
+ var userData = _userDataManager.GetUserData(action.UserId, item);
userData.LastPlayedDate = action.Date;
_userDataManager.UpdatePlayState(item, userData, action.PositionTicks);
@@ -775,6 +775,13 @@ namespace MediaBrowser.Server.Implementations.Sync
removeFromDevice = true;
}
}
+ else if (libraryItem != null && libraryItem.DateModified.Ticks != jobItem.ItemDateModifiedTicks && jobItem.ItemDateModifiedTicks > 0)
+ {
+ _logger.Info("Setting status to Queued for {0} because the media has been modified since the original sync.", jobItem.ItemId);
+ jobItem.Status = SyncJobItemStatus.Queued;
+ jobItem.Progress = 0;
+ requiresSaving = true;
+ }
}
else
{
@@ -881,6 +888,13 @@ namespace MediaBrowser.Server.Implementations.Sync
removeFromDevice = true;
}
}
+ else if (libraryItem != null && libraryItem.DateModified.Ticks != jobItem.ItemDateModifiedTicks && jobItem.ItemDateModifiedTicks > 0)
+ {
+ _logger.Info("Setting status to Queued for {0} because the media has been modified since the original sync.", jobItem.ItemId);
+ jobItem.Status = SyncJobItemStatus.Queued;
+ jobItem.Progress = 0;
+ requiresSaving = true;
+ }
}
else
{
@@ -1117,7 +1131,7 @@ namespace MediaBrowser.Server.Implementations.Sync
public SyncJobOptions GetAudioOptions(SyncJobItem jobItem, SyncJob job)
{
var options = GetSyncJobOptions(jobItem.TargetId, null, null);
-
+
if (job.Bitrate.HasValue)
{
options.DeviceProfile.MaxStaticBitrate = job.Bitrate.Value;
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
index 464e8aa58..6d31663b9 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
@@ -39,18 +39,18 @@ namespace MediaBrowser.Server.Implementations.Sync
_appPaths = appPaths;
}
- public async Task Initialize()
+ public async Task Initialize(IDbConnector dbConnector)
{
var dbFile = Path.Combine(_appPaths.DataPath, "sync14.db");
- _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
+ _connection = await dbConnector.Connect(dbFile).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)",
- "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, ItemName TEXT, MediaSourceId TEXT, JobId TEXT, TemporaryPath TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT, AdditionalFiles TEXT, MediaSource TEXT, IsMarkedForRemoval BIT, JobItemIndex INT)",
+ "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, ItemName TEXT, MediaSourceId TEXT, JobId TEXT, TemporaryPath TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT, AdditionalFiles TEXT, MediaSource TEXT, IsMarkedForRemoval BIT, JobItemIndex INT, ItemDateModifiedTicks BIGINT)",
"create index if not exists idx_SyncJobItems on SyncJobs(Id)",
//pragmas
@@ -63,6 +63,7 @@ namespace MediaBrowser.Server.Implementations.Sync
_connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT");
_connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT");
+ _connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT");
PrepareStatements();
}
@@ -127,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Sync
// _insertJobItemCommand
_insertJobItemCommand = _connection.CreateCommand();
- _insertJobItemCommand.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex)";
+ _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");
@@ -144,10 +145,11 @@ namespace MediaBrowser.Server.Implementations.Sync
_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 where Id=@Id";
+ _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");
@@ -164,10 +166,11 @@ namespace MediaBrowser.Server.Implementations.Sync
_updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSource");
_updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@IsMarkedForRemoval");
_updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobItemIndex");
+ _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemDateModifiedTicks");
}
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";
- private const string BaseJobItemSelectText = "select Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex from SyncJobItems";
+ private const string BaseJobItemSelectText = "select Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks from SyncJobItems";
public SyncJob GetJob(string id)
{
@@ -678,6 +681,7 @@ namespace MediaBrowser.Server.Implementations.Sync
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;
@@ -782,6 +786,11 @@ namespace MediaBrowser.Server.Implementations.Sync
info.IsMarkedForRemoval = reader.GetBoolean(13);
info.JobItemIndex = reader.GetInt32(14);
+ if (!reader.IsDBNull(15))
+ {
+ info.ItemDateModifiedTicks = reader.GetInt64(15);
+ }
+
return info;
}
diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
index 3e43ebe9b..ec91dc1b7 100644
--- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
+++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
@@ -36,10 +36,25 @@ namespace MediaBrowser.Server.Implementations.TV
? new string[] { }
: new[] { request.ParentId };
+ string presentationUniqueKey = null;
+ int? limit = null;
+ if (!string.IsNullOrWhiteSpace(request.SeriesId))
+ {
+ var series = _libraryManager.GetItemById(request.SeriesId);
+
+ if (series != null)
+ {
+ presentationUniqueKey = series.PresentationUniqueKey;
+ limit = 1;
+ }
+ }
+
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Series).Name },
- SortOrder = SortOrder.Ascending
+ SortOrder = SortOrder.Ascending,
+ PresentationUniqueKey = presentationUniqueKey,
+ Limit = limit
}, parentIds).Cast<Series>();
@@ -58,10 +73,25 @@ namespace MediaBrowser.Server.Implementations.TV
throw new ArgumentException("User not found");
}
+ string presentationUniqueKey = null;
+ int? limit = null;
+ if (!string.IsNullOrWhiteSpace(request.SeriesId))
+ {
+ var series = _libraryManager.GetItemById(request.SeriesId);
+
+ if (series != null)
+ {
+ presentationUniqueKey = series.PresentationUniqueKey;
+ limit = 1;
+ }
+ }
+
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Series).Name },
- SortOrder = SortOrder.Ascending
+ SortOrder = SortOrder.Ascending,
+ PresentationUniqueKey = presentationUniqueKey,
+ Limit = limit
}, parentsFolders.Select(i => i.Id.ToString("N"))).Cast<Series>();
@@ -76,30 +106,30 @@ namespace MediaBrowser.Server.Implementations.TV
// Avoid implicitly captured closure
var currentUser = user;
- return FilterSeries(request, series)
+ return series
.AsParallel()
.Select(i => GetNextUp(i, currentUser))
// Include if an episode was found, and either the series is not unwatched or the specific series was requested
.Where(i => i.Item1 != null && (!i.Item3 || !string.IsNullOrWhiteSpace(request.SeriesId)))
- .OrderByDescending(i =>
- {
- var episode = i.Item1;
+ //.OrderByDescending(i =>
+ //{
+ // var episode = i.Item1;
- var seriesUserData = _userDataManager.GetUserData(user.Id, episode.Series.GetUserDataKey());
+ // var seriesUserData = _userDataManager.GetUserData(user, episode.Series);
- if (seriesUserData.IsFavorite)
- {
- return 2;
- }
+ // if (seriesUserData.IsFavorite)
+ // {
+ // return 2;
+ // }
- if (seriesUserData.Likes.HasValue)
- {
- return seriesUserData.Likes.Value ? 1 : -1;
- }
+ // if (seriesUserData.Likes.HasValue)
+ // {
+ // return seriesUserData.Likes.Value ? 1 : -1;
+ // }
- return 0;
- })
- .ThenByDescending(i => i.Item2)
+ // return 0;
+ //})
+ .OrderByDescending(i => i.Item2)
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
.Select(i => i.Item1);
}
@@ -128,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.TV
// Go back starting with the most recent episodes
foreach (var episode in allEpisodes)
{
- var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey());
+ var userData = _userDataManager.GetUserData(user, episode);
if (userData.Played)
{
@@ -142,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.TV
}
else
{
- if (!episode.IsVirtualUnaired && (!episode.IsMissingEpisode || includeMissing))
+ if (!episode.IsVirtualUnaired && (includeMissing || !episode.IsMissingEpisode))
{
nextUp = episode;
}
@@ -154,24 +184,12 @@ namespace MediaBrowser.Server.Implementations.TV
return new Tuple<Episode, DateTime, bool>(nextUp, lastWatchedDate, false);
}
- var firstEpisode = allEpisodes.LastOrDefault(i => !i.IsVirtualUnaired && (!i.IsMissingEpisode || includeMissing) && !i.IsPlayed(user));
+ var firstEpisode = allEpisodes.LastOrDefault(i => !i.IsVirtualUnaired && (includeMissing || !i.IsMissingEpisode) && !i.IsPlayed(user));
// Return the first episode
return new Tuple<Episode, DateTime, bool>(firstEpisode, DateTime.MinValue, true);
}
- private IEnumerable<Series> FilterSeries(NextUpQuery request, IEnumerable<Series> items)
- {
- if (!string.IsNullOrWhiteSpace(request.SeriesId))
- {
- var id = new Guid(request.SeriesId);
-
- items = items.Where(i => i.Id == id);
- }
-
- return items;
- }
-
private QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, int? totalRecordLimit, NextUpQuery query)
{
var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
index 911dbb0cb..161f771a9 100644
--- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -153,7 +153,8 @@ namespace MediaBrowser.Server.Implementations.UserViews
CollectionType.HomeVideos,
CollectionType.BoxSets,
CollectionType.Playlists,
- CollectionType.Photos
+ CollectionType.Photos,
+ string.Empty
};
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 66aede029..dce839b57 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -8,5 +8,6 @@
<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" />
- <package id="SocketHttpListener" version="1.0.0.29" targetFramework="net45" />
+ <package id="SimpleInjector" version="3.1.3" targetFramework="net45" />
+ <package id="SocketHttpListener" version="1.0.0.30" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index 237325cfe..b61281f1b 100644
--- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -32,6 +32,7 @@
<CreatePackage>true</CreatePackage>
<PackageSigningKey>Developer ID Installer</PackageSigningKey>
<UseRefCounting>false</UseRefCounting>
+ <Profiling>false</Profiling>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
@@ -47,6 +48,7 @@
<CreatePackage>true</CreatePackage>
<PackageSigningKey>Developer ID Installer</PackageSigningKey>
<UseRefCounting>false</UseRefCounting>
+ <Profiling>false</Profiling>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|AnyCPU' ">
<DebugType>full</DebugType>
@@ -63,6 +65,7 @@
<EnableCodeSigning>false</EnableCodeSigning>
<EnablePackageSigning>false</EnablePackageSigning>
<UseRefCounting>false</UseRefCounting>
+ <Profiling>false</Profiling>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -89,7 +92,6 @@
<Folder Include="Resources\" />
<Folder Include="Native\" />
<Folder Include="Resources\swagger-ui\" />
- <Folder Include="Resources\dashboard-ui\" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppDelegate.cs" />
@@ -260,9 +262,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\addplugin.html">
<Link>Resources\dashboard-ui\addplugin.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\advanced.html">
- <Link>Resources\dashboard-ui\advanced.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\appservices.html">
<Link>Resources\dashboard-ui\appservices.html</Link>
</BundleResource>
@@ -281,9 +280,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\channels.html">
<Link>Resources\dashboard-ui\channels.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\channelsettings.html">
- <Link>Resources\dashboard-ui\channelsettings.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\cinemamodeconfiguration.html">
<Link>Resources\dashboard-ui\cinemamodeconfiguration.html</Link>
</BundleResource>
@@ -317,9 +313,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dlnaprofiles.html">
<Link>Resources\dashboard-ui\dlnaprofiles.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dlnaserversettings.html">
- <Link>Resources\dashboard-ui\dlnaserversettings.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dlnasettings.html">
<Link>Resources\dashboard-ui\dlnasettings.html</Link>
</BundleResource>
@@ -425,9 +418,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\metadata.html">
<Link>Resources\dashboard-ui\metadata.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\metadataadvanced.html">
- <Link>Resources\dashboard-ui\metadataadvanced.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\metadataimages.html">
<Link>Resources\dashboard-ui\metadataimages.html</Link>
</BundleResource>
@@ -524,9 +514,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\streamingsettings.html">
<Link>Resources\dashboard-ui\streamingsettings.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\support.html">
- <Link>Resources\dashboard-ui\support.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\supporterkey.html">
<Link>Resources\dashboard-ui\supporterkey.html</Link>
</BundleResource>
@@ -929,6 +916,21 @@
<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>
@@ -1334,6 +1336,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\scrollhelper.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\scrollhelper.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\scrollstyles.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\scrollstyles.css</Link>
+ </BundleResource>
+ <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\usersettings.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\usersettings.js</Link>
</BundleResource>
@@ -1571,6 +1579,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\images\persistentimagefetcher.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\images\persistentimagefetcher.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\input\api.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\input\api.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\loading\loading-lite.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\loading\loading-lite.js</Link>
</BundleResource>
@@ -1970,6 +1981,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-a11y-keys-behavior\iron-a11y-keys-behavior.html">
<Link>Resources\dashboard-ui\bower_components\iron-a11y-keys-behavior\iron-a11y-keys-behavior.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-a11y-keys-behavior\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-a11y-keys-behavior\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-a11y-keys-behavior\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-a11y-keys-behavior\demo\index.html</Link>
</BundleResource>
@@ -2162,9 +2176,18 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\index.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\url-bar.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\url-bar.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\demo\index.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\demo\url-bar.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\demo\url-bar.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-demo-helpers\test\basic.html">
<Link>Resources\dashboard-ui\bower_components\iron-demo-helpers\test\basic.html</Link>
</BundleResource>
@@ -2513,6 +2536,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\iron-input.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\iron-input.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-input\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\demo\index.html</Link>
</BundleResource>
@@ -2528,9 +2554,60 @@
<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-location\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\.gitignore">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\.gitignore</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\.travis.yml">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\.travis.yml</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\CONTRIBUTING.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\CONTRIBUTING.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\README.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\README.md</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>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\iron-location.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\iron-location.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\iron-query-params.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\iron-query-params.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\iron-location\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\demo\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\demo\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\demo\iron-query-params.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\demo\iron-query-params.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\index.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\index.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\initialization-cases.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\initialization-cases.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\initialization-iframe.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\initialization-iframe.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\initialization-tests.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\initialization-tests.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-location\test\iron-location.html">
+ <Link>Resources\dashboard-ui\bower_components\iron-location\test\iron-location.html</Link>
+ </BundleResource>
+ <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-media-query\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-media-query\.bower.json</Link>
</BundleResource>
@@ -2702,12 +2779,18 @@
<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>
@@ -2858,6 +2941,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-selector\iron-selector.html">
<Link>Resources\dashboard-ui\bower_components\iron-selector\iron-selector.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-selector\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\iron-selector\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-selector\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-selector\demo\index.html</Link>
</BundleResource>
@@ -3353,6 +3439,36 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\jstree\src\themes\default-dark\throbber.gif">
<Link>Resources\dashboard-ui\bower_components\jstree\src\themes\default-dark\throbber.gif</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\.bower.json">
+ <Link>Resources\dashboard-ui\bower_components\libjass\.bower.json</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\CHANGELOG.md">
+ <Link>Resources\dashboard-ui\bower_components\libjass\CHANGELOG.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\LICENSE">
+ <Link>Resources\dashboard-ui\bower_components\libjass\LICENSE</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\README.md">
+ <Link>Resources\dashboard-ui\bower_components\libjass\README.md</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\libjass.css">
+ <Link>Resources\dashboard-ui\bower_components\libjass\libjass.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\libjass.js">
+ <Link>Resources\dashboard-ui\bower_components\libjass\libjass.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\libjass.js.map">
+ <Link>Resources\dashboard-ui\bower_components\libjass\libjass.js.map</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\libjass.min.js">
+ <Link>Resources\dashboard-ui\bower_components\libjass\libjass.min.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\libjass.min.js.map">
+ <Link>Resources\dashboard-ui\bower_components\libjass\libjass.min.js.map</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\libjass\package.json">
+ <Link>Resources\dashboard-ui\bower_components\libjass\package.json</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\marked\.bower.json">
<Link>Resources\dashboard-ui\bower_components\marked\.bower.json</Link>
</BundleResource>
@@ -4163,6 +4279,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\web-animations.html">
<Link>Resources\dashboard-ui\bower_components\neon-animation\web-animations.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\neon-animation\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\animations\cascaded-animation.html">
<Link>Resources\dashboard-ui\bower_components\neon-animation\animations\cascaded-animation.html</Link>
</BundleResource>
@@ -4307,6 +4426,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-lazy.html">
+ <Link>Resources\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages-lazy.html</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages.html">
<Link>Resources\dashboard-ui\bower_components\neon-animation\test\neon-animated-pages.html</Link>
</BundleResource>
@@ -4751,6 +4873,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-textarea.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-textarea.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\paper-input\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\demo\index.html</Link>
</BundleResource>
@@ -4820,6 +4945,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-item\paper-item.html">
<Link>Resources\dashboard-ui\bower_components\paper-item\paper-item.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-item\.github\ISSUE_TEMPLATE.md">
+ <Link>Resources\dashboard-ui\bower_components\paper-item\.github\ISSUE_TEMPLATE.md</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-item\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-item\demo\index.html</Link>
</BundleResource>
@@ -4925,6 +5053,9 @@
<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>
@@ -8879,6 +9010,12 @@
<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>
@@ -8888,6 +9025,9 @@
<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>
@@ -9068,6 +9208,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\logindefault.png">
<Link>Resources\dashboard-ui\css\images\logindefault.png</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\logo.png">
+ <Link>Resources\dashboard-ui\css\images\logo.png</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\logo536.png">
<Link>Resources\dashboard-ui\css\images\logo536.png</Link>
</BundleResource>
@@ -9161,9 +9304,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\editor\missingprimaryimage.png">
<Link>Resources\dashboard-ui\css\images\editor\missingprimaryimage.png</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\editor\missingtrailer.png">
- <Link>Resources\dashboard-ui\css\images\editor\missingtrailer.png</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\items\detail\audio.png">
<Link>Resources\dashboard-ui\css\images\items\detail\audio.png</Link>
</BundleResource>
@@ -9338,9 +9478,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\legacy\fnchecked.js">
<Link>Resources\dashboard-ui\legacy\fnchecked.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\legacy\objectassign.js">
- <Link>Resources\dashboard-ui\legacy\objectassign.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\legacy\selectmenu.js">
<Link>Resources\dashboard-ui\legacy\selectmenu.js</Link>
</BundleResource>
@@ -9350,9 +9487,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\addpluginpage.js">
<Link>Resources\dashboard-ui\scripts\addpluginpage.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\advancedconfigurationpage.js">
- <Link>Resources\dashboard-ui\scripts\advancedconfigurationpage.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\alphapicker.js">
<Link>Resources\dashboard-ui\scripts\alphapicker.js</Link>
</BundleResource>
@@ -9377,9 +9511,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channels.js">
<Link>Resources\dashboard-ui\scripts\channels.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channelsettings.js">
- <Link>Resources\dashboard-ui\scripts\channelsettings.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channelslatest.js">
<Link>Resources\dashboard-ui\scripts\channelslatest.js</Link>
</BundleResource>
@@ -9416,9 +9547,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dlnaprofiles.js">
<Link>Resources\dashboard-ui\scripts\dlnaprofiles.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dlnaserversettings.js">
- <Link>Resources\dashboard-ui\scripts\dlnaserversettings.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dlnasettings.js">
<Link>Resources\dashboard-ui\scripts\dlnasettings.js</Link>
</BundleResource>
@@ -9464,6 +9592,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\gamesystemspage.js">
<Link>Resources\dashboard-ui\scripts\gamesystemspage.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\homefavorites.js">
+ <Link>Resources\dashboard-ui\scripts\homefavorites.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\homenextup.js">
<Link>Resources\dashboard-ui\scripts\homenextup.js</Link>
</BundleResource>
@@ -9578,9 +9709,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\mediaplayer.js">
<Link>Resources\dashboard-ui\scripts\mediaplayer.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\metadataadvanced.js">
- <Link>Resources\dashboard-ui\scripts\metadataadvanced.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\metadataconfigurationpage.js">
<Link>Resources\dashboard-ui\scripts\metadataconfigurationpage.js</Link>
</BundleResource>
@@ -9917,9 +10045,6 @@
<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\server.json">
- <Link>Resources\dashboard-ui\strings\server.json</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\sl-SI.json">
<Link>Resources\dashboard-ui\strings\sl-SI.json</Link>
</BundleResource>
diff --git a/MediaBrowser.Server.Mac/MenuBarIcon.cs b/MediaBrowser.Server.Mac/MenuBarIcon.cs
index 51ba7f432..865f45057 100644
--- a/MediaBrowser.Server.Mac/MenuBarIcon.cs
+++ b/MediaBrowser.Server.Mac/MenuBarIcon.cs
@@ -88,17 +88,17 @@ namespace MediaBrowser.Server.Mac
private void Community(NSObject sender)
{
- BrowserLauncher.OpenCommunity(Logger);
+ BrowserLauncher.OpenCommunity(MainClass.AppHost);
}
private void Configure(NSObject sender)
{
- BrowserLauncher.OpenDashboard(MainClass.AppHost, Logger);
+ BrowserLauncher.OpenDashboard(MainClass.AppHost);
}
private void Browse(NSObject sender)
{
- BrowserLauncher.OpenWebClient(MainClass.AppHost, Logger);
+ BrowserLauncher.OpenWebClient(MainClass.AppHost);
}
public void Terminate()
diff --git a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
index 33df83b2f..67ad96859 100644
--- a/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mac/Native/BaseMonoApp.cs
@@ -7,6 +7,8 @@ using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Server.Startup.Common.FFMpeg;
+using System.Diagnostics;
namespace MediaBrowser.Server.Mac
{
@@ -106,6 +108,79 @@ namespace MediaBrowser.Server.Mac
{
}
+ public void LaunchUrl(string url)
+ {
+ var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = url
+ },
+
+ EnableRaisingEvents = true,
+ };
+
+ process.Exited += ProcessExited;
+
+ process.Start();
+ }
+
+ /// <summary>
+ /// Processes the exited.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
+ private static void ProcessExited(object sender, EventArgs e)
+ {
+ ((Process)sender).Dispose();
+ }
+
+ public FFMpegInstallInfo GetFfmpegInstallInfo()
+ {
+ return GetInfo(Environment);
+ }
+
+ public static FFMpegInstallInfo GetInfo(NativeEnvironment environment)
+ {
+ var info = new FFMpegInstallInfo();
+
+ info.ArchiveType = "7z";
+
+ switch (environment.SystemArchitecture)
+ {
+ case Architecture.X86_X64:
+ info.Version = "20160124";
+ break;
+ case Architecture.X86:
+ info.Version = "20150110";
+ break;
+ }
+
+ info.DownloadUrls = GetDownloadUrls(environment);
+
+ return info;
+ }
+
+ private static string[] GetDownloadUrls(NativeEnvironment environment)
+ {
+ switch (environment.SystemArchitecture)
+ {
+ case Architecture.X86_X64:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.8.5.7z"
+ };
+ case Architecture.X86:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x86-2.5.3.7z"
+ };
+ }
+
+ // No version available
+ return new string[] { };
+ }
+
public INetworkManager CreateNetworkManager(ILogger logger)
{
return new NetworkManager(logger);
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index 48d2df7ce..b71877e17 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -76,12 +76,17 @@
<Reference Include="MediaBrowser.IsoMounting.Linux">
<HintPath>..\ThirdParty\MediaBrowser.IsoMounting.Linux\MediaBrowser.IsoMounting.Linux.dll</HintPath>
</Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Data.SQLite">
+ <HintPath>..\ThirdParty\System.Data.SQLite.ManagedOnly\1.0.94.0\System.Data.SQLite.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Native\BaseMonoApp.cs" />
+ <Compile Include="Native\SqliteExtensions.cs" />
<Compile Include="Networking\CertificateGenerator.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 6d19c3275..a012a19a3 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.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem;
@@ -17,9 +18,12 @@ namespace MediaBrowser.Server.Mono.Native
public abstract class BaseMonoApp : INativeApp
{
protected StartupOptions StartupOptions { get; private set; }
- protected BaseMonoApp(StartupOptions startupOptions)
+ protected ILogger Logger { get; private set; }
+
+ protected BaseMonoApp(StartupOptions startupOptions, ILogger logger)
{
StartupOptions = startupOptions;
+ Logger = logger;
}
/// <summary>
@@ -69,6 +73,11 @@ namespace MediaBrowser.Server.Mono.Native
}
+ public void AllowSystemStandby()
+ {
+
+ }
+
public List<Assembly> GetAssembliesWithParts()
{
var list = new List<Assembly>();
@@ -217,6 +226,16 @@ namespace MediaBrowser.Server.Mono.Native
return GetInfo(Environment);
}
+ public void LaunchUrl(string url)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IDbConnector GetDbConnector()
+ {
+ return new DbConnector(Logger);
+ }
+
public static FFMpegInstallInfo GetInfo(NativeEnvironment environment)
{
var info = new FFMpegInstallInfo();
diff --git a/MediaBrowser.Server.Mono/Native/NativeApp.cs b/MediaBrowser.Server.Mono/Native/NativeApp.cs
index c73a96497..c0874a1d8 100644
--- a/MediaBrowser.Server.Mono/Native/NativeApp.cs
+++ b/MediaBrowser.Server.Mono/Native/NativeApp.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Server.Startup.Common;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Startup.Common;
namespace MediaBrowser.Server.Mono.Native
{
@@ -7,8 +8,8 @@ namespace MediaBrowser.Server.Mono.Native
/// </summary>
internal class NativeApp : BaseMonoApp
{
- public NativeApp(StartupOptions startupOptions)
- : base(startupOptions)
+ public NativeApp(StartupOptions startupOptions, ILogger logger)
+ : base(startupOptions, logger)
{
}
diff --git a/MediaBrowser.Server.Mono/Native/SqliteExtensions.cs b/MediaBrowser.Server.Mono/Native/SqliteExtensions.cs
new file mode 100644
index 000000000..385a7d0c5
--- /dev/null
+++ b/MediaBrowser.Server.Mono/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.Mono.Native
+{
+ /// <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/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 2a0609449..32de45242 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -79,7 +79,7 @@ namespace MediaBrowser.Server.Mono
var fileSystem = new ManagedFileSystem(new PatternsLogger(logManager.GetLogger("FileSystem")), false, false);
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
- var nativeApp = new NativeApp(options);
+ var nativeApp = new NativeApp(options, logManager.GetLogger("App"));
_appHost = new ApplicationHost(appPaths, logManager, options, fileSystem, "emby.mono.zip", nativeApp);
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 93dbe2945..ae839e6ee 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -410,13 +410,16 @@ namespace MediaBrowser.Server.Startup.Common
UserRepository = await GetUserRepository().ConfigureAwait(false);
RegisterSingleInstance(UserRepository);
- DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
+ var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
+ DisplayPreferencesRepository = displayPreferencesRepo;
RegisterSingleInstance(DisplayPreferencesRepository);
- ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
+ var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager);
+ ItemRepository = itemRepo;
RegisterSingleInstance(ItemRepository);
- ProviderRepository = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
+ var providerRepo = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
+ ProviderRepository = providerRepo;
RegisterSingleInstance(ProviderRepository);
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
@@ -440,7 +443,7 @@ namespace MediaBrowser.Server.Startup.Common
LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, this);
RegisterSingleInstance(LibraryMonitor);
- ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager);
+ ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer);
RegisterSingleInstance(ProviderManager);
SeriesOrderManager = new SeriesOrderManager();
@@ -515,7 +518,7 @@ namespace MediaBrowser.Server.Startup.Common
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
RegisterSingleInstance(UserViewManager);
- var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager);
+ var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder);
RegisterSingleInstance<IContentDirectory>(contentDirectory);
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager);
@@ -541,7 +544,7 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance(NativeApp.GetPowerManagement());
var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
- await sharingRepo.Initialize().ConfigureAwait(false);
+ await sharingRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
RegisterSingleInstance<ISsdpHandler>(new SsdpHandler(LogManager.GetLogger("SsdpHandler"), ServerConfigurationManager, this));
@@ -557,10 +560,12 @@ namespace MediaBrowser.Server.Startup.Common
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager);
RegisterSingleInstance(SubtitleEncoder);
-
- await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false);
- await ConfigureItemRepositories().ConfigureAwait(false);
+
+ await displayPreferencesRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
await ConfigureUserDataRepositories().ConfigureAwait(false);
+ await itemRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ await providerRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
+ ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
await ConfigureNotificationsRepository().ConfigureAwait(false);
progress.Report(100);
@@ -658,7 +663,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
return repo;
}
@@ -677,7 +682,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
return repo;
}
@@ -686,7 +691,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
return repo;
}
@@ -695,7 +700,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
return repo;
}
@@ -704,7 +709,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
return repo;
}
@@ -717,7 +722,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
NotificationsRepository = repo;
@@ -725,28 +730,6 @@ namespace MediaBrowser.Server.Startup.Common
}
/// <summary>
- /// Configures the repositories.
- /// </summary>
- /// <returns>Task.</returns>
- private async Task ConfigureDisplayPreferencesRepositories()
- {
- await DisplayPreferencesRepository.Initialize().ConfigureAwait(false);
- }
-
- /// <summary>
- /// Configures the item repositories.
- /// </summary>
- /// <returns>Task.</returns>
- private async Task ConfigureItemRepositories()
- {
- await ItemRepository.Initialize().ConfigureAwait(false);
-
- await ProviderRepository.Initialize().ConfigureAwait(false);
-
- ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
- }
-
- /// <summary>
/// Configures the user data repositories.
/// </summary>
/// <returns>Task.</returns>
@@ -754,7 +737,7 @@ namespace MediaBrowser.Server.Startup.Common
{
var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
- await repo.Initialize().ConfigureAwait(false);
+ await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false);
((UserDataManager)UserDataManager).Repository = repo;
}
@@ -1404,5 +1387,10 @@ namespace MediaBrowser.Server.Startup.Common
return externalDns;
}
}
+
+ public void LaunchUrl(string url)
+ {
+ NativeApp.LaunchUrl(url);
+ }
}
}
diff --git a/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs b/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
index a4504f25a..db48d1110 100644
--- a/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
+++ b/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
@@ -15,87 +15,58 @@ namespace MediaBrowser.Server.Startup.Common.Browser
/// </summary>
/// <param name="page">The page.</param>
/// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- public static void OpenDashboardPage(string page, IServerApplicationHost appHost, ILogger logger)
+ public static void OpenDashboardPage(string page, IServerApplicationHost appHost)
{
var url = appHost.GetLocalApiUrl("localhost") + "/web/" + page;
- OpenUrl(url, logger);
+ OpenUrl(appHost, url);
}
/// <summary>
/// Opens the community.
/// </summary>
- /// <param name="logger">The logger.</param>
- public static void OpenCommunity(ILogger logger)
+ public static void OpenCommunity(IServerApplicationHost appHost)
{
- OpenUrl("http://emby.media/community", logger);
+ OpenUrl(appHost, "http://emby.media/community");
}
/// <summary>
/// Opens the web client.
/// </summary>
/// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- public static void OpenWebClient(IServerApplicationHost appHost, ILogger logger)
+ public static void OpenWebClient(IServerApplicationHost appHost)
{
- OpenDashboardPage("index.html", appHost, logger);
+ OpenDashboardPage("index.html", appHost);
}
/// <summary>
/// Opens the dashboard.
/// </summary>
/// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- public static void OpenDashboard(IServerApplicationHost appHost, ILogger logger)
+ public static void OpenDashboard(IServerApplicationHost appHost)
{
- OpenDashboardPage("dashboard.html", appHost, logger);
+ OpenDashboardPage("dashboard.html", appHost);
}
/// <summary>
/// Opens the URL.
/// </summary>
/// <param name="url">The URL.</param>
- /// <param name="logger">The logger.</param>
- private static void OpenUrl(string url, ILogger logger)
+ private static void OpenUrl(IServerApplicationHost appHost, string url)
{
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = url
- },
-
- EnableRaisingEvents = true,
- };
-
- process.Exited += ProcessExited;
-
try
{
- process.Start();
+ appHost.LaunchUrl(url);
+ }
+ catch (NotImplementedException)
+ {
+
}
catch (Exception ex)
{
- logger.ErrorException("Error launching url: {0}", ex, url);
-
- Console.WriteLine("Error launching url: {0}", ex.Message);
+ Console.WriteLine("Error launching url: " + url);
Console.WriteLine(ex.Message);
-
-//#if !__MonoCS__
-// System.Windows.Forms.MessageBox.Show("There was an error launching your web browser. Please check your default browser settings.");
-//#endif
}
}
-
- /// <summary>
- /// Processes the exited.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- private static void ProcessExited(object sender, EventArgs e)
- {
- ((Process)sender).Dispose();
- }
}
}
diff --git a/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs b/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
index 20d4c6b2a..dbfd6f4e8 100644
--- a/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
+++ b/MediaBrowser.Server.Startup.Common/EntryPoints/KeepServerAwake.cs
@@ -27,28 +27,27 @@ namespace MediaBrowser.Server.Startup.Common.EntryPoints
_timer = new PeriodicTimer(obj =>
{
var now = DateTime.UtcNow;
- if (_sessionManager.Sessions.Any(i => (now - i.LastActivityDate).TotalMinutes < 15))
+ var nativeApp = ((ApplicationHost)_appHost).NativeApp;
+
+ try
+ {
+ if (_sessionManager.Sessions.Any(i => (now - i.LastActivityDate).TotalMinutes < 15))
+ {
+ nativeApp.PreventSystemStandby();
+ }
+ else
+ {
+ nativeApp.AllowSystemStandby();
+ }
+ }
+ catch (Exception ex)
{
- KeepAlive();
+ _logger.ErrorException("Error resetting system standby timer", ex);
}
}, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
}
- private void KeepAlive()
- {
- var nativeApp = ((ApplicationHost)_appHost).NativeApp;
-
- try
- {
- nativeApp.PreventSystemStandby();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error resetting system standby timer", ex);
- }
- }
-
public void Dispose()
{
if (_timer != null)
diff --git a/MediaBrowser.Server.Startup.Common/EntryPoints/StartupWizard.cs b/MediaBrowser.Server.Startup.Common/EntryPoints/StartupWizard.cs
index 854fa44c1..f9d173c59 100644
--- a/MediaBrowser.Server.Startup.Common/EntryPoints/StartupWizard.cs
+++ b/MediaBrowser.Server.Startup.Common/EntryPoints/StartupWizard.cs
@@ -46,7 +46,7 @@ namespace MediaBrowser.Server.Startup.Common.EntryPoints
/// </summary>
private void LaunchStartupWizard()
{
- BrowserLauncher.OpenDashboardPage("wizardstart.html", _appHost, _logger);
+ BrowserLauncher.OpenDashboardPage("wizardstart.html", _appHost);
}
/// <summary>
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
index 5ba5fb44a..0ae021407 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
catch
{
}
+ //_logger.Debug("ffmpeg decoder query result: {0}", output ?? string.Empty);
var found = new List<string>();
var required = new[]
@@ -78,6 +79,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
catch
{
}
+ //_logger.Debug("ffmpeg encoder query result: {0}", output ?? string.Empty);
var found = new List<string>();
var required = new[]
@@ -89,8 +91,8 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
//"libvpx",
//"libvpx-vp9",
"aac",
- "ac3",
"libmp3lame",
+ "libopus",
//"libvorbis",
"srt"
};
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 121d4192e..c13d3624e 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/MediaBrowser.Server.Startup.Common/INativeApp.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging;
using System.Collections.Generic;
using System.Reflection;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
namespace MediaBrowser.Server.Startup.Common
@@ -93,6 +94,8 @@ namespace MediaBrowser.Server.Startup.Common
/// </summary>
void PreventSystemStandby();
+ void AllowSystemStandby();
+
/// <summary>
/// Gets the power management.
/// </summary>
@@ -100,5 +103,9 @@ namespace MediaBrowser.Server.Startup.Common
IPowerManagement GetPowerManagement();
FFMpegInstallInfo GetFfmpegInstallInfo();
+
+ void LaunchUrl(string url);
+
+ IDbConnector GetDbConnector();
}
}
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index ac1b7ca99..dc61dcda8 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -273,11 +273,13 @@ namespace MediaBrowser.ServerApplication
}
private static ServerNotifyIcon _serverNotifyIcon;
+ private static TaskScheduler _mainTaskScheduler;
private static void ShowTrayIcon()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
_serverNotifyIcon = new ServerNotifyIcon(_appHost.LogManager, _appHost, _appHost.ServerConfigurationManager, _appHost.LocalizationManager);
+ _mainTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Application.Run();
}
@@ -317,7 +319,19 @@ namespace MediaBrowser.ServerApplication
{
if (e.Reason == SessionSwitchReason.SessionLogon)
{
- BrowserLauncher.OpenDashboard(_appHost, _logger);
+ BrowserLauncher.OpenDashboard(_appHost);
+ }
+ }
+
+ public static void Invoke(Action action)
+ {
+ if (_isRunningAsService)
+ {
+ action();
+ }
+ else
+ {
+ Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _mainTaskScheduler ?? TaskScheduler.Current);
}
}
@@ -555,9 +569,10 @@ namespace MediaBrowser.ServerApplication
private static void ShutdownWindowsApplication()
{
- _logger.Info("Calling Application.Exit");
- Application.Exit();
+ //_logger.Info("Calling Application.Exit");
+ //Application.Exit();
+ _logger.Info("Calling Environment.Exit");
Environment.Exit(0);
_logger.Info("Calling ApplicationTaskCompletionSource.SetResult");
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 291e63dac..366d4b608 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -13,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkProfile />
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -81,9 +83,9 @@
<Reference Include="System.Configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
- <Reference Include="System.Data.SQLite, Version=1.0.94.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\System.Data.SQLite.Core.1.0.94.0\lib\net45\System.Data.SQLite.dll</HintPath>
+ <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>
+ <Private>True</Private>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.ServiceProcess" />
@@ -112,6 +114,7 @@
</Compile>
<Compile Include="MainStartup.cs" />
<Compile Include="Native\LnkShortcutHandler.cs" />
+ <Compile Include="Native\SqliteExtensions.cs" />
<Compile Include="Native\Standby.cs" />
<Compile Include="Native\ServerAuthorization.cs" />
<Compile Include="Native\WindowsApp.cs" />
@@ -139,8 +142,6 @@
<None Include="App.config" />
<None Include="app.manifest" />
<EmbeddedResource Include="Native\RegisterServer.bat" />
- <EmbeddedResource Include="ffmpeg\ffmpegx64.7z" />
- <EmbeddedResource Include="ffmpeg\ffmpegx86.7z" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
@@ -156,14 +157,6 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
- <Content Include="..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\x64\SQLite.Interop.dll">
- <Link>x64\SQLite.Interop.dll</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\x86\SQLite.Interop.dll">
- <Link>x86\SQLite.Interop.dll</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="..\Tools\Installation\MediaBrowser.InstallUtil.dll">
<Link>MediaBrowser.InstallUtil.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -1116,6 +1109,13 @@
<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')" />
+ <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'))" />
+ </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.
<Target Name="BeforeBuild">
@@ -1123,5 +1123,4 @@
<Target Name="AfterBuild">
</Target>
-->
- <Import Project="..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\System.Data.SQLite.Core.targets')" />
</Project> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Native/SqliteExtensions.cs b/MediaBrowser.ServerApplication/Native/SqliteExtensions.cs
new file mode 100644
index 000000000..1cde2ea13
--- /dev/null
+++ b/MediaBrowser.ServerApplication/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.ServerApplication.Native
+{
+ /// <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.ServerApplication/Native/Standby.cs b/MediaBrowser.ServerApplication/Native/Standby.cs
index 274c72b25..919709538 100644
--- a/MediaBrowser.ServerApplication/Native/Standby.cs
+++ b/MediaBrowser.ServerApplication/Native/Standby.cs
@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using System;
+using System.Runtime.InteropServices;
namespace MediaBrowser.ServerApplication.Native
{
@@ -7,11 +8,33 @@ namespace MediaBrowser.ServerApplication.Native
/// </summary>
public static class Standby
{
- public static void PreventSystemStandby()
+ public static void PreventSleepAndMonitorOff()
{
- SystemHelper.ResetStandbyTimer();
+ NativeMethods.SetThreadExecutionState(NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED | NativeMethods.ES_DISPLAY_REQUIRED);
}
+ public static void PreventSleep()
+ {
+ NativeMethods.SetThreadExecutionState(NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED);
+ }
+
+ // Clear EXECUTION_STATE flags to allow the system to sleep and turn off monitor normally
+ public static void AllowSleep()
+ {
+ NativeMethods.SetThreadExecutionState(NativeMethods.ES_CONTINUOUS);
+ }
+
+ internal static class NativeMethods
+ {
+ // Import SetThreadExecutionState Win32 API and necessary flags
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern uint SetThreadExecutionState(uint esFlags);
+ public const uint ES_CONTINUOUS = 0x80000000;
+ public const uint ES_SYSTEM_REQUIRED = 0x00000001;
+ public const uint ES_DISPLAY_REQUIRED = 0x00000002;
+ }
+
+ [Flags]
internal enum EXECUTION_STATE : uint
{
ES_NONE = 0,
@@ -21,16 +44,5 @@ namespace MediaBrowser.ServerApplication.Native
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000
}
-
- public class SystemHelper
- {
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
-
- public static void ResetStandbyTimer()
- {
- EXECUTION_STATE es = SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED);
- }
- }
}
}
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index 146a4372b..f5abcf336 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -1,13 +1,18 @@
-using MediaBrowser.Common.Net;
+using System;
+using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Startup.Common;
using MediaBrowser.ServerApplication.Networking;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Reflection;
+using System.Windows.Forms;
using CommonIO;
using MediaBrowser.Controller.Power;
+using MediaBrowser.Server.Implementations.Persistence;
using MediaBrowser.Server.Startup.Common.FFMpeg;
+using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem;
namespace MediaBrowser.ServerApplication.Native
{
@@ -134,7 +139,12 @@ namespace MediaBrowser.ServerApplication.Native
public void PreventSystemStandby()
{
- Standby.PreventSystemStandby();
+ MainStartup.Invoke(Standby.PreventSleep);
+ }
+
+ public void AllowSystemStandby()
+ {
+ MainStartup.Invoke(Standby.AllowSleep);
}
public IPowerManagement GetPowerManagement()
@@ -148,24 +158,72 @@ namespace MediaBrowser.ServerApplication.Native
info.FFMpegFilename = "ffmpeg.exe";
info.FFProbeFilename = "ffprobe.exe";
- info.Version = "20160401";
+ info.Version = "20160410";
info.ArchiveType = "7z";
- info.IsEmbedded = true;
+ info.IsEmbedded = false;
info.DownloadUrls = GetDownloadUrls();
return info;
}
+ public void LaunchUrl(string url)
+ {
+ var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = url
+ },
+
+ EnableRaisingEvents = true,
+ };
+
+ process.Exited += ProcessExited;
+
+ try
+ {
+ process.Start();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error launching url: {0}", ex, url);
+
+ throw;
+ }
+ }
+
+ public IDbConnector GetDbConnector()
+ {
+ return new DbConnector(_logger);
+ }
+
+ /// <summary>
+ /// Processes the exited.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
+ private static void ProcessExited(object sender, EventArgs e)
+ {
+ ((Process)sender).Dispose();
+ }
+
private string[] GetDownloadUrls()
{
switch (Environment.SystemArchitecture)
{
case Architecture.X86_X64:
- return new[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx64.7z" };
+ 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[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx86.7z" };
+ 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[] { };
}
}
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index 978a29db0..cc9061fcd 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -29,6 +29,7 @@ namespace MediaBrowser.ServerApplication.Networking
/// <returns>IEnumerable{NetworkShare}.</returns>
public IEnumerable<NetworkShare> GetNetworkShares(string path)
{
+ Logger.Info("Getting network shares from {0}", path);
return new ShareCollection(path).OfType<Share>().Select(ToNetworkShare);
}
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkShares.cs b/MediaBrowser.ServerApplication/Networking/NetworkShares.cs
index 91bd167b8..f9a59203d 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkShares.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkShares.cs
@@ -390,7 +390,9 @@ namespace MediaBrowser.ServerApplication.Networking
Type t = (2 == level) ? typeof(SHARE_INFO_2) : typeof(SHARE_INFO_1);
int offset = Marshal.SizeOf(t);
- for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += offset)
+ var lpItem = pBuffer.ToInt64();
+
+ for (int i = 0; i < entriesRead; i++, lpItem += offset)
{
IntPtr pItem = new IntPtr(lpItem);
if (1 == level)
diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
index 673c6cddd..27816db5a 100644
--- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
+++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
@@ -36,10 +36,15 @@ namespace MediaBrowser.ServerApplication
set
{
Action act = () => notifyIcon1.Visible = false;
- contextMenuStrip1.Invoke(act);
+ Invoke(act);
}
}
+ public void Invoke(Action action)
+ {
+ contextMenuStrip1.Invoke(action);
+ }
+
public ServerNotifyIcon(ILogManager logManager,
IServerApplicationHost appHost,
IServerConfigurationManager configurationManager,
@@ -163,7 +168,7 @@ namespace MediaBrowser.ServerApplication
void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
- BrowserLauncher.OpenDashboard(_appHost, _logger);
+ BrowserLauncher.OpenDashboard(_appHost);
}
private void LocalizeText()
@@ -194,17 +199,17 @@ namespace MediaBrowser.ServerApplication
void cmdBrowse_Click(object sender, EventArgs e)
{
- BrowserLauncher.OpenWebClient(_appHost, _logger);
+ BrowserLauncher.OpenWebClient(_appHost);
}
void cmdCommunity_Click(object sender, EventArgs e)
{
- BrowserLauncher.OpenCommunity(_logger);
+ BrowserLauncher.OpenCommunity(_appHost);
}
void cmdConfigure_Click(object sender, EventArgs e)
{
- BrowserLauncher.OpenDashboard(_appHost, _logger);
+ BrowserLauncher.OpenDashboard(_appHost);
}
void cmdRestart_Click(object sender, EventArgs e)
diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id
deleted file mode 100644
index b0542b75f..000000000
--- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-9dc10b022537738edce7eb71aa8dd4adbfee2c7b \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id
deleted file mode 100644
index 3939ec44d..000000000
--- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-00fa1afa35fbd0a7e97ad7956e42ae17f6882f64 \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 1c86a02ae..2d4baae25 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.94.0" targetFramework="net45" requireReinstallation="true" />
+ <package id="System.Data.SQLite.Core" version="1.0.101.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 376978790..1569c1fc5 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -316,7 +316,7 @@ namespace MediaBrowser.WebDashboard.Api
DeleteFilesByExtension(bowerPath, ".txt");
DeleteFilesByExtension(bowerPath, ".map");
DeleteFilesByExtension(bowerPath, ".md");
- DeleteFilesByExtension(bowerPath, ".json");
+ DeleteFilesByExtension(bowerPath, ".json", "strings\\");
DeleteFilesByExtension(bowerPath, ".gz");
DeleteFilesByExtension(bowerPath, ".bat");
DeleteFilesByExtension(bowerPath, ".sh");
@@ -401,7 +401,7 @@ namespace MediaBrowser.WebDashboard.Api
}
}
- private void DeleteFilesByExtension(string path, string extension)
+ private void DeleteFilesByExtension(string path, string extension, string exclude = null)
{
var files = _fileSystem.GetFiles(path, true)
.Where(i => string.Equals(i.Extension, extension, StringComparison.OrdinalIgnoreCase))
@@ -409,6 +409,13 @@ namespace MediaBrowser.WebDashboard.Api
foreach (var file in files)
{
+ if (!string.IsNullOrWhiteSpace(exclude))
+ {
+ if (file.FullName.IndexOf(exclude, StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ continue;
+ }
+ }
_fileSystem.DeleteFile(file.FullName);
}
}
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index b633d1590..d8de98abe 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -384,7 +384,7 @@ namespace MediaBrowser.WebDashboard.Api
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
- sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'unsafe-inline' 'unsafe-eval' data:;\">");
+ sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'unsafe-inline' 'unsafe-eval' data: filesystem:;\">");
}
sb.Append("<link rel=\"manifest\" href=\"manifest.json\">");
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index f84fe058a..e6d690f27 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -128,16 +128,22 @@
<Content Include="dashboard-ui\components\guestinviter\guestinviter.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\ironcardlist\ironcardlist.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\ironcardlist\ironcardlist.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\components\metadataeditor\metadataeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\metadataeditor\personeditor.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\recordingcreator\recordingcreator.js">
+ <Content Include="dashboard-ui\components\recordingeditor\recordingeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\recordingcreator\recordingcreator.template.html">
+ <Content Include="dashboard-ui\components\recordingeditor\recordingeditor.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\remotecontrol.js">
@@ -146,7 +152,7 @@
<Content Include="dashboard-ui\components\remotecontrolautoplay.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\servertestermessage.js">
+ <Content Include="dashboard-ui\components\scrollthreshold.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\viewcontainer-lite.js">
@@ -155,6 +161,9 @@
<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>
@@ -221,12 +230,6 @@
<Content Include="dashboard-ui\components\playlisteditor\playlisteditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\components\tvguide\tvguide.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\components\tvguide\tvguide.template.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\devices\ie\ie.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -365,12 +368,6 @@
<Content Include="dashboard-ui\scripts\shared.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\sharingmanager.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\components\sharingwidget.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\supporterkeypage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -464,26 +461,12 @@
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.icons.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.theme.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\thirdparty\paper-button-style.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\.gitignore" />
- <Content Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\css\social-share-kit.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.js" />
- <Content Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\js\social-share-kit.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\components\tvproviders\schedulesdirect.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -973,9 +956,6 @@
<Content Include="dashboard-ui\scripts\livetvchannel.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\livetvtimer.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\livetvrecordinglist.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -988,12 +968,6 @@
<Content Include="dashboard-ui\scripts\livetvstatus.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\livetvtimer.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\scripts\livetvtimers.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\editorsidebar.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1709,6 +1683,9 @@
<None Include="dashboard-ui\strings\fr-CA.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
+ <None Include="dashboard-ui\strings\fr-FR.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
<None Include="dashboard-ui\strings\hu.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -1724,20 +1701,6 @@
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.popup.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <None Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.map">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.eot">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.ttf">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\dist\fonts\social-share-kit.woff">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\LICENSE" />
- <None Include="dashboard-ui\thirdparty\social-share-kit-1.0.4\README.md" />
<None Include="dashboard-ui\voice\grammar\en-US.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 75b5498c5..d020a73fe 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -662,7 +662,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
if (!string.IsNullOrWhiteSpace(val))
{
- val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", "http://www.youtube.com/watch?v=", StringComparison.OrdinalIgnoreCase);
+ val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", "https://www.youtube.com/watch?v=", StringComparison.OrdinalIgnoreCase);
hasTrailer.AddTrailerUrl(val, false);
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
index 5ce8d30ad..c1dd92987 100644
--- a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
@@ -9,7 +9,7 @@ using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
- public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasChangeMonitor
+ public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor
where T : IHasMetadata, new()
{
protected IFileSystem FileSystem;
@@ -57,7 +57,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
- public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+ public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var file = GetXmlFile(new ItemInfo(item), directoryService);
@@ -66,7 +66,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
return false;
}
- return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > date;
+ return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved;
}
public string Name
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index e37b83f4b..d2e09d4eb 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -889,7 +889,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
// This is what xbmc expects
- return url.Replace("http://www.youtube.com/watch?v=",
+ return url.Replace("https://www.youtube.com/watch?v=",
"plugin://plugin.video.youtube/?action=play_video&videoid=",
StringComparison.OrdinalIgnoreCase);
}
@@ -936,7 +936,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
return;
}
- var userdata = userDataRepo.GetUserData(user.Id, item.GetUserDataKey());
+ var userdata = userDataRepo.GetUserData(user, item);
writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString().ToLower());
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 0ae08c4ad..d17fab368 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.645</version>
+ <version>3.0.647</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,9 +12,9 @@
<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.645" />
- <dependency id="NLog" version="4.2.3" />
- <dependency id="SimpleInjector" version="3.1.2" />
+ <dependency id="MediaBrowser.Common" version="3.0.647" />
+ <dependency id="NLog" version="4.3.1" />
+ <dependency id="SimpleInjector" version="3.1.3" />
</dependencies>
</metadata>
<files>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index b9bce00d0..f0f6320f0 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.645</version>
+ <version>3.0.647</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index 3af1b91e2..6c47b62eb 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Model.Signed</id>
- <version>3.0.645</version>
+ <version>3.0.647</version>
<title>MediaBrowser.Model - Signed Edition</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 d48b421c5..8060298ca 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.645</version>
+ <version>3.0.647</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.645" />
+ <dependency id="MediaBrowser.Common" version="3.0.647" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>
diff --git a/OpenSubtitlesHandler/Utilities.cs b/OpenSubtitlesHandler/Utilities.cs
index 2ae116521..d26c76b7c 100644
--- a/OpenSubtitlesHandler/Utilities.cs
+++ b/OpenSubtitlesHandler/Utilities.cs
@@ -32,7 +32,7 @@ namespace OpenSubtitlesHandler
/// </summary>
public sealed class Utilities
{
- private const string XML_RPC_SERVER = "http://api.opensubtitles.org/xml-rpc";
+ private const string XML_RPC_SERVER = "https://api.opensubtitles.org/xml-rpc";
/// <summary>
/// Compute movie hash
@@ -195,7 +195,7 @@ namespace OpenSubtitlesHandler
RequestContentBytes = request,
RequestContentType = "text/xml",
UserAgent = userAgent,
- Host = "api.opensubtitles.org:80",
+ Host = "api.opensubtitles.org:443",
Url = XML_RPC_SERVER,
// Response parsing will fail with this enabled