aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Drawing/Common/ImageHeader.cs3
-rw-r--r--Emby.Drawing/Emby.Drawing.csproj20
-rw-r--r--Emby.Drawing/GDI/DynamicImageHelpers.cs1
-rw-r--r--Emby.Drawing/GDI/GDIImageEncoder.cs33
-rw-r--r--Emby.Drawing/GDI/empty.pngbin0 -> 158 bytes
-rw-r--r--Emby.Drawing/IImageEncoder.cs18
-rw-r--r--Emby.Drawing/ImageMagick/ImageMagickEncoder.cs46
-rw-r--r--Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs28
-rw-r--r--Emby.Drawing/ImageMagick/StripCollageBuilder.cs18
-rw-r--r--Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs8
-rw-r--r--Emby.Drawing/ImageProcessor.cs115
-rw-r--r--Emby.Drawing/NullImageEncoder.cs64
-rw-r--r--Emby.Drawing/packages.config2
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs7
-rw-r--r--MediaBrowser.Api/AppThemeService.cs100
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs1
-rw-r--r--MediaBrowser.Api/Dlna/DlnaServerService.cs1
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs13
-rw-r--r--MediaBrowser.Api/Images/ImageByNameService.cs22
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs77
-rw-r--r--MediaBrowser.Api/Images/RemoteImageService.cs7
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs9
-rw-r--r--MediaBrowser.Api/ItemRefreshService.cs8
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs14
-rw-r--r--MediaBrowser.Api/Library/LibraryHelpers.cs11
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs10
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs45
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs4
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj19
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs113
-rw-r--r--MediaBrowser.Api/Playback/Dash/MpegDashService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs12
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs18
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs1
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs16
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs1
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs5
-rw-r--r--MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs1
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs2
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs13
-rw-r--r--MediaBrowser.Api/PlaylistService.cs26
-rw-r--r--MediaBrowser.Api/PluginService.cs18
-rw-r--r--MediaBrowser.Api/Reports/Common/HeaderMetadata.cs1
-rw-r--r--MediaBrowser.Api/Reports/Common/ItemViewType.cs1
-rw-r--r--MediaBrowser.Api/Reports/Data/ReportBuilder.cs19
-rw-r--r--MediaBrowser.Api/Reports/Model/ReportRow.cs4
-rw-r--r--MediaBrowser.Api/Reports/ReportsService.cs1
-rw-r--r--MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs2
-rw-r--r--MediaBrowser.Api/Social/SharingService.cs18
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs3
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs8
-rw-r--r--MediaBrowser.Api/Sync/SyncService.cs10
-rw-r--r--MediaBrowser.Api/System/SystemService.cs11
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs3
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs1
-rw-r--r--MediaBrowser.Api/UserLibrary/UserViewsService.cs34
-rw-r--r--MediaBrowser.Api/VideosService.cs1
-rw-r--r--MediaBrowser.Api/packages.config4
-rw-r--r--MediaBrowser.Common.Implementations/Archiving/ZipClient.cs19
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs27
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs36
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs7
-rw-r--r--MediaBrowser.Common.Implementations/Devices/DeviceId.cs18
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs145
-rw-r--r--MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs433
-rw-r--r--MediaBrowser.Common.Implementations/Logging/NlogManager.cs4
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj18
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs22
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs55
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs11
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs3
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs8
-rw-r--r--MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs68
-rw-r--r--MediaBrowser.Common.Implementations/Security/RegRecord.cs1
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs11
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs11
-rw-r--r--MediaBrowser.Common.Implementations/Updates/InstallationManager.cs9
-rw-r--r--MediaBrowser.Common.Implementations/packages.config6
-rw-r--r--MediaBrowser.Common/IO/IFileSystem.cs165
-rw-r--r--MediaBrowser.Common/MediaBrowser.Common.csproj1
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs2
-rw-r--r--MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs5
-rw-r--r--MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs6
-rw-r--r--MediaBrowser.Common/Security/ISecurityManager.cs7
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs2
-rw-r--r--MediaBrowser.Controller/Channels/ChannelAudioItem.cs13
-rw-r--r--MediaBrowser.Controller/Channels/ChannelFolderItem.cs10
-rw-r--r--MediaBrowser.Controller/Channels/ChannelVideoItem.cs19
-rw-r--r--MediaBrowser.Controller/Channels/IChannelFactory.cs14
-rw-r--r--MediaBrowser.Controller/Channels/IChannelItem.cs6
-rw-r--r--MediaBrowser.Controller/Channels/IChannelManager.cs2
-rw-r--r--MediaBrowser.Controller/Channels/IChannelMediaItem.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs16
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs21
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs242
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs10
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs98
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs10
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs38
-rw-r--r--MediaBrowser.Controller/Entities/IHasMetadata.cs21
-rw-r--r--MediaBrowser.Controller/Entities/IHasPreferredMetadataLanguage.cs21
-rw-r--r--MediaBrowser.Controller/Entities/IHasProgramAttributes.cs2
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs7
-rw-r--r--MediaBrowser.Controller/Entities/ItemImageInfo.cs17
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs6
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs11
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs6
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs3
-rw-r--r--MediaBrowser.Controller/Entities/User.cs11
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs30
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs67
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs29
-rw-r--r--MediaBrowser.Controller/IO/FileData.cs7
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs6
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs44
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs16
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs5
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs22
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs25
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs53
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs23
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj29
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs7
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs15
-rw-r--r--MediaBrowser.Controller/Net/IHttpServer.cs5
-rw-r--r--MediaBrowser.Controller/Net/StaticResultOptions.cs1
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs7
-rw-r--r--MediaBrowser.Controller/Playlists/IPlaylistManager.cs8
-rw-r--r--MediaBrowser.Controller/Providers/BaseItemXmlParser.cs23
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs41
-rw-r--r--MediaBrowser.Controller/Providers/DynamicImageResponse.cs2
-rw-r--r--MediaBrowser.Controller/Providers/EpisodeIdentity.cs12
-rw-r--r--MediaBrowser.Controller/Providers/EpisodeInfo.cs18
-rw-r--r--MediaBrowser.Controller/Providers/IDirectoryService.cs14
-rw-r--r--MediaBrowser.Controller/Providers/IHasIdentities.cs14
-rw-r--r--MediaBrowser.Controller/Providers/IItemIdentity.cs7
-rw-r--r--MediaBrowser.Controller/Providers/IItemIdentityConverter.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IItemIdentityProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs12
-rw-r--r--MediaBrowser.Controller/Providers/ImageRefreshMode.cs8
-rw-r--r--MediaBrowser.Controller/Providers/ItemIdentifier.cs63
-rw-r--r--MediaBrowser.Controller/Providers/ItemIdentities.cs15
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/LocalImageInfo.cs4
-rw-r--r--MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs6
-rw-r--r--MediaBrowser.Controller/Providers/MetadataStatus.cs30
-rw-r--r--MediaBrowser.Controller/Providers/SeasonIdentity.cs11
-rw-r--r--MediaBrowser.Controller/Providers/SeasonInfo.cs18
-rw-r--r--MediaBrowser.Controller/Providers/SeriesIdentity.cs9
-rw-r--r--MediaBrowser.Controller/Providers/SeriesInfo.cs20
-rw-r--r--MediaBrowser.Controller/Resolvers/IItemResolver.cs10
-rw-r--r--MediaBrowser.Controller/Themes/IAppThemeManager.cs38
-rw-r--r--MediaBrowser.Controller/Themes/InternalThemeImage.cs31
-rw-r--r--MediaBrowser.Controller/packages.config4
-rw-r--r--MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs642
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs2
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs20
-rw-r--r--MediaBrowser.Dlna/DlnaManager.cs11
-rw-r--r--MediaBrowser.Dlna/Main/DlnaEntryPoint.cs2
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj11
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs3
-rw-r--r--MediaBrowser.Dlna/Ssdp/Datagram.cs20
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHandler.cs12
-rw-r--r--MediaBrowser.Dlna/packages.config5
-rw-r--r--MediaBrowser.LocalMetadata/BaseXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs1
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs1
-rw-r--r--MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs1
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs27
-rw-r--r--MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj12
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs7
-rw-r--r--MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs16
-rw-r--r--MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs9
-rw-r--r--MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs24
-rw-r--r--MediaBrowser.LocalMetadata/packages.config5
-rw-r--r--MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs18
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs57
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs38
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs102
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs1
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj8
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs46
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs25
-rw-r--r--MediaBrowser.MediaEncoding/packages.config2
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj9
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj9
-rw-r--r--MediaBrowser.Model/Configuration/DlnaOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs29
-rw-r--r--MediaBrowser.Model/Devices/DeviceInfo.cs5
-rw-r--r--MediaBrowser.Model/Dlna/ConditionProcessor.cs13
-rw-r--r--MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs6
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs5
-rw-r--r--MediaBrowser.Model/Dlna/ProfileConditionValue.cs3
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs33
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs15
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleProfile.cs13
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs16
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs6
-rw-r--r--MediaBrowser.Model/Entities/VirtualFolderInfo.cs12
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj16
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs5
-rw-r--r--MediaBrowser.Model/System/SystemInfo.cs8
-rw-r--r--MediaBrowser.Model/Themes/AppTheme.cs22
-rw-r--r--MediaBrowser.Model/Themes/AppThemeInfo.cs9
-rw-r--r--MediaBrowser.Model/Themes/ThemeImage.cs18
-rw-r--r--MediaBrowser.Providers/Books/BookMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs3
-rw-r--r--MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Channels/ChannelMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Channels/VideoChannelItemMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Folders/DefaultImageProvider.cs25
-rw-r--r--MediaBrowser.Providers/Folders/FolderMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Folders/UserViewMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Games/GameMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Games/GameSystemMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Genres/GenreImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/Genres/GenreMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/ImagesByName/ImageUtils.cs7
-rw-r--r--MediaBrowser.Providers/LiveTv/AudioRecordingService.cs1
-rw-r--r--MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/LiveTv/VideoRecordingService.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs76
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs74
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs142
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs114
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs10
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj12
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs3
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs3
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs11
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs3
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs10
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs9
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs32
-rw-r--r--MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs41
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs59
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbSearch.cs112
-rw-r--r--MediaBrowser.Providers/Movies/MovieMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs9
-rw-r--r--MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs10
-rw-r--r--MediaBrowser.Providers/Music/AlbumMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs3
-rw-r--r--MediaBrowser.Providers/Music/AudioDbArtistProvider.cs3
-rw-r--r--MediaBrowser.Providers/Music/AudioMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs3
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs5
-rw-r--r--MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs9
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/MusicVideoMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/MusicGenres/MusicGenreImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbItemProvider.cs42
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonProvider.cs3
-rw-r--r--MediaBrowser.Providers/People/PersonMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Photos/PhotoMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Photos/PhotoProvider.cs159
-rw-r--r--MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Studios/StudioMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs1
-rw-r--r--MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs2
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs3
-rw-r--r--MediaBrowser.Providers/TV/DummySeasonProvider.cs10
-rw-r--r--MediaBrowser.Providers/TV/EpisodeMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/TV/FanArtSeasonProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs9
-rw-r--r--MediaBrowser.Providers/TV/FanartSeriesProvider.cs5
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs12
-rw-r--r--MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs7
-rw-r--r--MediaBrowser.Providers/TV/SeasonMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs8
-rw-r--r--MediaBrowser.Providers/TV/SeriesPostScanTask.cs14
-rw-r--r--MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs3
-rw-r--r--MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs135
-rw-r--r--MediaBrowser.Providers/TV/TvdbPrescanTask.cs11
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeasonIdentityProvider.cs51
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs36
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs15
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesProvider.cs228
-rw-r--r--MediaBrowser.Providers/Users/UserMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Videos/VideoMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/Years/YearMetadataService.cs1
-rw-r--r--MediaBrowser.Providers/packages.config4
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs82
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs180
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs35
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionManager.cs61
-rw-r--r--MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs33
-rw-r--r--MediaBrowser.Server.Implementations/Connect/ConnectManager.cs55
-rw-r--r--MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceManager.cs10
-rw-r--r--MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs33
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs3
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs5
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs76
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs1
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs1
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs80
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs11
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs4
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs45
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs6
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs20
-rw-r--r--MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs278
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs30
-rw-r--r--MediaBrowser.Server.Implementations/Library/MusicManager.cs17
-rw-r--r--MediaBrowser.Server.Implementations/Library/ResolverHelper.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs40
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs3
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserManager.cs12
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs105
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs18
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs56
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs249
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs8
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs6
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs6
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs6
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs129
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs145
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs65
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs63
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs167
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs14
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs42
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs98
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ar.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json7
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ca.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/core.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/cs.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/da.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/de.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/el.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-GB.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/en-US.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es-AR.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es-MX.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/es.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/fi.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/fr.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/gsw.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/he.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/hr.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/it.json59
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/kk.json13
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ko.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ms.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/nb.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/nl.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pl.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ro.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/ru.json39
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/sv.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/tr.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/uk.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/vi.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json7
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json177
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json3
-rw-r--r--MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj42
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs7
-rw-r--r--MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs6
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/IConfigurableNotificationService.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/InternalNotificationService.cs21
-rw-r--r--MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs23
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs86
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs219
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs304
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs9
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs906
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs633
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs23
-rw-r--r--MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs73
-rw-r--r--MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs22
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs42
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs12
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MediaSync.cs23
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs21
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncManager.cs64
-rw-r--r--MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs168
-rw-r--r--MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs10
-rw-r--r--MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs23
-rw-r--r--MediaBrowser.Server.Implementations/packages.config7
-rw-r--r--MediaBrowser.Server.Mac.userprefs21
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj9
-rw-r--r--MediaBrowser.Server.Mono/Native/BaseMonoApp.cs15
-rw-r--r--MediaBrowser.Server.Mono/Native/NativeApp.cs5
-rw-r--r--MediaBrowser.Server.Mono/Program.cs7
-rw-r--r--MediaBrowser.Server.Mono/packages.config2
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs91
-rw-r--r--MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs21
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs20
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs17
-rw-r--r--MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs92
-rw-r--r--MediaBrowser.Server.Startup.Common/INativeApp.cs6
-rw-r--r--MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs53
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj15
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs45
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs35
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs39
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs48
-rw-r--r--MediaBrowser.Server.Startup.Common/Migrations/RenameXbmcOptions.cs56
-rw-r--r--MediaBrowser.Server.Startup.Common/UnhandledExceptionWriter.cs4
-rw-r--r--MediaBrowser.Server.Startup.Common/packages.config2
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs10
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj18
-rw-r--r--MediaBrowser.ServerApplication/Native/Autorun.cs1
-rw-r--r--MediaBrowser.ServerApplication/Native/NativeFileSystem.cs419
-rw-r--r--MediaBrowser.ServerApplication/Native/WindowsApp.cs14
-rw-r--r--MediaBrowser.ServerApplication/ServerNotifyIcon.cs64
-rw-r--r--MediaBrowser.ServerApplication/packages.config2
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/unit.srt2
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs38
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs9
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj321
-rw-r--r--MediaBrowser.WebDashboard/packages.config4
-rw-r--r--MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj11
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs12
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs1
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs1
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs43
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs1
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs3
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs1
-rw-r--r--MediaBrowser.XbmcMetadata/packages.config5
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec6
-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/MovieHasher.cs12
-rw-r--r--OpenSubtitlesHandler/Utilities.cs2
-rw-r--r--SharedVersion.cs2
512 files changed, 7427 insertions, 6548 deletions
diff --git a/Emby.Drawing/Common/ImageHeader.cs b/Emby.Drawing/Common/ImageHeader.cs
index b66bd71ea..266dcdfb8 100644
--- a/Emby.Drawing/Common/ImageHeader.cs
+++ b/Emby.Drawing/Common/ImageHeader.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace Emby.Drawing.Common
{
@@ -220,4 +221,4 @@ namespace Emby.Drawing.Common
throw new ArgumentException(ErrorMessage);
}
}
-}
+} \ No newline at end of file
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
index ab53f7550..e9911a12d 100644
--- a/Emby.Drawing/Emby.Drawing.csproj
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -12,7 +12,6 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,10 +31,20 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
+ <Reference Include="policy.2.0.taglib-sharp">
+ <HintPath>..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
@@ -44,11 +53,15 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
+ <Reference Include="taglib-sharp">
+ <HintPath>..\packages\taglib.2.1.0.0\lib\taglib-sharp.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="Common\ImageHeader.cs" />
<Compile Include="GDI\DynamicImageHelpers.cs" />
<Compile Include="GDI\GDIImageEncoder.cs" />
<Compile Include="GDI\ImageExtensions.cs" />
@@ -56,13 +69,13 @@
<Compile Include="GDI\PlayedIndicatorDrawer.cs" />
<Compile Include="GDI\UnplayedCountIndicator.cs" />
<Compile Include="IImageEncoder.cs" />
- <Compile Include="Common\ImageHeader.cs" />
<Compile Include="ImageHelpers.cs" />
<Compile Include="ImageMagick\ImageMagickEncoder.cs" />
<Compile Include="ImageMagick\StripCollageBuilder.cs" />
<Compile Include="ImageProcessor.cs" />
<Compile Include="ImageMagick\PercentPlayedDrawer.cs" />
<Compile Include="ImageMagick\PlayedIndicatorDrawer.cs" />
+ <Compile Include="NullImageEncoder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ImageMagick\UnplayedCountIndicator.cs" />
</ItemGroup>
@@ -87,6 +100,9 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="GDI\empty.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/Emby.Drawing/GDI/DynamicImageHelpers.cs b/Emby.Drawing/GDI/DynamicImageHelpers.cs
index b4a63b31e..5cedf820d 100644
--- a/Emby.Drawing/GDI/DynamicImageHelpers.cs
+++ b/Emby.Drawing/GDI/DynamicImageHelpers.cs
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
+using CommonIO;
namespace Emby.Drawing.GDI
{
diff --git a/Emby.Drawing/GDI/GDIImageEncoder.cs b/Emby.Drawing/GDI/GDIImageEncoder.cs
index 7e3ca530b..530613741 100644
--- a/Emby.Drawing/GDI/GDIImageEncoder.cs
+++ b/Emby.Drawing/GDI/GDIImageEncoder.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Logging;
using System;
@@ -8,6 +7,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
+using CommonIO;
using ImageFormat = MediaBrowser.Model.Drawing.ImageFormat;
namespace Emby.Drawing.GDI
@@ -22,7 +22,20 @@ namespace Emby.Drawing.GDI
_fileSystem = fileSystem;
_logger = logger;
- _logger.Info("GDI image processor initialized");
+ LogInfo();
+ }
+
+ private void LogInfo()
+ {
+ _logger.Info("GDIImageEncoder starting");
+ using (var stream = GetType().Assembly.GetManifestResourceStream(GetType().Namespace + ".empty.png"))
+ {
+ using (var img = Image.FromStream(stream))
+ {
+
+ }
+ }
+ _logger.Info("GDIImageEncoder started");
}
public string[] SupportedInputFormats
@@ -66,7 +79,7 @@ namespace Emby.Drawing.GDI
{
using (var croppedImage = image.CropWhitespace())
{
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
using (var outputStream = _fileSystem.GetFileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
{
@@ -120,7 +133,7 @@ namespace Emby.Drawing.GDI
var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat);
- Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
// Save to the cache location
using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
@@ -252,5 +265,15 @@ namespace Emby.Drawing.GDI
{
get { return "GDI"; }
}
+
+ public bool SupportsImageCollageCreation
+ {
+ get { return true; }
+ }
+
+ public bool SupportsImageEncoding
+ {
+ get { return true; }
+ }
}
}
diff --git a/Emby.Drawing/GDI/empty.png b/Emby.Drawing/GDI/empty.png
new file mode 100644
index 000000000..42e2b375e
--- /dev/null
+++ b/Emby.Drawing/GDI/empty.png
Binary files differ
diff --git a/Emby.Drawing/IImageEncoder.cs b/Emby.Drawing/IImageEncoder.cs
index 29261dbdb..4469075a6 100644
--- a/Emby.Drawing/IImageEncoder.cs
+++ b/Emby.Drawing/IImageEncoder.cs
@@ -17,12 +17,6 @@ namespace Emby.Drawing
/// <value>The supported output formats.</value>
ImageFormat[] SupportedOutputFormats { get; }
/// <summary>
- /// Gets the size of the image.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>ImageSize.</returns>
- ImageSize GetImageSize(string path);
- /// <summary>
/// Crops the white space.
/// </summary>
/// <param name="inputPath">The input path.</param>
@@ -49,5 +43,17 @@ namespace Emby.Drawing
/// </summary>
/// <value>The name.</value>
string Name { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether [supports image collage creation].
+ /// </summary>
+ /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
+ bool SupportsImageCollageCreation { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether [supports image encoding].
+ /// </summary>
+ /// <value><c>true</c> if [supports image encoding]; otherwise, <c>false</c>.</value>
+ bool SupportsImageEncoding { get; }
}
}
diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
index 6ff40d1cf..ed0760ee3 100644
--- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
namespace Emby.Drawing.ImageMagick
{
@@ -16,14 +17,16 @@ namespace Emby.Drawing.ImageMagick
private readonly ILogger _logger;
private readonly IApplicationPaths _appPaths;
private readonly IHttpClient _httpClient;
+ private readonly IFileSystem _fileSystem;
- public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient)
+ public ImageMagickEncoder(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
_httpClient = httpClient;
+ _fileSystem = fileSystem;
- LogImageMagickVersion();
+ LogVersion();
}
public string[] SupportedInputFormats
@@ -64,7 +67,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- private void LogImageMagickVersion()
+ private void LogVersion()
{
_logger.Info("ImageMagick version: " + Wand.VersionString);
TestWebp();
@@ -77,16 +80,16 @@ namespace Emby.Drawing.ImageMagick
try
{
var tmpPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".webp");
- Directory.CreateDirectory(Path.GetDirectoryName(tmpPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath));
using (var wand = new MagickWand(1, 1, new PixelWand("none", 1)))
{
wand.SaveImage(tmpPath);
}
}
- catch (Exception ex)
+ catch
{
- _logger.ErrorException("Error loading webp: ", ex);
+ //_logger.ErrorException("Error loading webp: ", ex);
_webpAvailable = false;
}
}
@@ -100,6 +103,7 @@ namespace Emby.Drawing.ImageMagick
wand.CurrentImage.TrimImage(10);
wand.SaveImage(outputPath);
}
+ SaveDelay();
}
public ImageSize GetImageSize(string path)
@@ -159,6 +163,7 @@ namespace Emby.Drawing.ImageMagick
}
}
}
+ SaveDelay();
}
/// <summary>
@@ -181,14 +186,14 @@ namespace Emby.Drawing.ImageMagick
{
var currentImageSize = new ImageSize(imageWidth, imageHeight);
- var task = new PlayedIndicatorDrawer(_appPaths, _httpClient).DrawPlayedIndicator(wand, currentImageSize);
+ var task = new PlayedIndicatorDrawer(_appPaths, _httpClient, _fileSystem).DrawPlayedIndicator(wand, currentImageSize);
Task.WaitAll(task);
}
else if (options.UnplayedCount.HasValue)
{
var currentImageSize = new ImageSize(imageWidth, imageHeight);
- new UnplayedCountIndicator(_appPaths).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value);
+ new UnplayedCountIndicator(_appPaths, _fileSystem).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value);
}
if (options.PercentPlayed > 0)
@@ -209,16 +214,25 @@ namespace Emby.Drawing.ImageMagick
if (ratio >= 1.4)
{
- new StripCollageBuilder(_appPaths).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
}
else if (ratio >= .9)
{
- new StripCollageBuilder(_appPaths).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
}
else
{
- new StripCollageBuilder(_appPaths).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height, options.Text);
}
+
+ SaveDelay();
+ }
+
+ private void SaveDelay()
+ {
+ // For some reason the images are not always getting released right away
+ var task = Task.Delay(300);
+ Task.WaitAll(task);
}
public string Name
@@ -240,5 +254,15 @@ namespace Emby.Drawing.ImageMagick
throw new ObjectDisposedException(GetType().Name);
}
}
+
+ public bool SupportsImageCollageCreation
+ {
+ get { return true; }
+ }
+
+ public bool SupportsImageEncoding
+ {
+ get { return true; }
+ }
}
}
diff --git a/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs b/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs
index 1c751de1f..0870b3767 100644
--- a/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs
+++ b/Emby.Drawing/ImageMagick/PlayedIndicatorDrawer.cs
@@ -5,6 +5,8 @@ using MediaBrowser.Model.Drawing;
using System;
using System.IO;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace Emby.Drawing.ImageMagick
{
@@ -14,12 +16,14 @@ namespace Emby.Drawing.ImageMagick
private const int OffsetFromTopRightCorner = 38;
private readonly IApplicationPaths _appPaths;
- private readonly IHttpClient _iHttpClient;
+ private readonly IHttpClient _iHttpClient;
+ private readonly IFileSystem _fileSystem;
- public PlayedIndicatorDrawer(IApplicationPaths appPaths, IHttpClient iHttpClient)
+ public PlayedIndicatorDrawer(IApplicationPaths appPaths, IHttpClient iHttpClient, IFileSystem fileSystem)
{
_appPaths = appPaths;
_iHttpClient = iHttpClient;
+ _fileSystem = fileSystem;
}
public async Task DrawPlayedIndicator(MagickWand wand, ImageSize imageSize)
@@ -38,7 +42,7 @@ namespace Emby.Drawing.ImageMagick
pixel.Opacity = 0;
pixel.Color = "white";
draw.FillColor = pixel;
- draw.Font = await DownloadFont("webdings.ttf", "https://github.com/MediaBrowser/Emby.Resources/raw/master/fonts/webdings.ttf", _appPaths, _iHttpClient).ConfigureAwait(false);
+ draw.Font = await DownloadFont("webdings.ttf", "https://github.com/MediaBrowser/Emby.Resources/raw/master/fonts/webdings.ttf", _appPaths, _iHttpClient, _fileSystem).ConfigureAwait(false);
draw.FontSize = FontSize;
draw.FontStyle = FontStyleType.NormalStyle;
draw.TextAlignment = TextAlignType.CenterAlign;
@@ -52,18 +56,18 @@ namespace Emby.Drawing.ImageMagick
}
}
- internal static string ExtractFont(string name, IApplicationPaths paths)
+ internal static string ExtractFont(string name, IApplicationPaths paths, IFileSystem fileSystem)
{
var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
- if (File.Exists(filePath))
+ if (fileSystem.FileExists(filePath))
{
return filePath;
}
var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name;
var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf");
- Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
+ fileSystem.CreateDirectory(Path.GetDirectoryName(tempPath));
using (var stream = typeof(PlayedIndicatorDrawer).Assembly.GetManifestResourceStream(namespacePath))
{
@@ -73,11 +77,11 @@ namespace Emby.Drawing.ImageMagick
}
}
- Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+ fileSystem.CreateDirectory(Path.GetDirectoryName(filePath));
try
{
- File.Copy(tempPath, filePath, false);
+ fileSystem.CopyFile(tempPath, filePath, false);
}
catch (IOException)
{
@@ -87,11 +91,11 @@ namespace Emby.Drawing.ImageMagick
return tempPath;
}
- internal static async Task<string> DownloadFont(string name, string url, IApplicationPaths paths, IHttpClient httpClient)
+ internal static async Task<string> DownloadFont(string name, string url, IApplicationPaths paths, IHttpClient httpClient, IFileSystem fileSystem)
{
var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
- if (File.Exists(filePath))
+ if (fileSystem.FileExists(filePath))
{
return filePath;
}
@@ -103,11 +107,11 @@ namespace Emby.Drawing.ImageMagick
}).ConfigureAwait(false);
- Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+ fileSystem.CreateDirectory(Path.GetDirectoryName(filePath));
try
{
- File.Copy(tempPath, filePath, false);
+ fileSystem.CopyFile(tempPath, filePath, false);
}
catch (IOException)
{
diff --git a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
index 7ed0f36e2..a7e3a155d 100644
--- a/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
+++ b/Emby.Drawing/ImageMagick/StripCollageBuilder.cs
@@ -2,16 +2,20 @@
using MediaBrowser.Common.Configuration;
using System;
using System.Collections.Generic;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace Emby.Drawing.ImageMagick
{
public class StripCollageBuilder
{
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public StripCollageBuilder(IApplicationPaths appPaths)
+ public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height, string text)
@@ -145,17 +149,17 @@ namespace Emby.Drawing.ImageMagick
private MagickWand BuildPosterCollageWand(List<string> paths, int width, int height)
{
- var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
+ var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
{
var wand = new MagickWand(width, height);
wand.OpenImage("gradient:#111111-#111111");
using (var draw = new DrawingWand())
{
- var iSlice = Convert.ToInt32(width * 0.225);
+ var iSlice = Convert.ToInt32(width * 0.3);
int iTrans = Convert.ToInt32(height * .25);
int iHeight = Convert.ToInt32(height * .65);
- var horizontalImagePadding = Convert.ToInt32(width * 0.0275);
+ var horizontalImagePadding = Convert.ToInt32(width * 0.0366);
foreach (var element in wandImages.ImageList)
{
@@ -350,14 +354,14 @@ namespace Emby.Drawing.ImageMagick
private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height)
{
- var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
+ var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
{
var wand = new MagickWand(width, height);
wand.OpenImage("gradient:#111111-#111111");
using (var draw = new DrawingWand())
{
- var iSlice = Convert.ToInt32(width * .225);
+ var iSlice = Convert.ToInt32(width * .3);
int iTrans = Convert.ToInt32(height * .25);
int iHeight = Convert.ToInt32(height * .63);
var horizontalImagePadding = Convert.ToInt32(width * 0.02);
@@ -490,7 +494,7 @@ namespace Emby.Drawing.ImageMagick
private string MontserratLightFont
{
- get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths); }
+ get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths, _fileSystem); }
}
}
}
diff --git a/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs b/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs
index dd25004d6..d3d9c1e7a 100644
--- a/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs
+++ b/Emby.Drawing/ImageMagick/UnplayedCountIndicator.cs
@@ -1,7 +1,9 @@
using ImageMagickSharp;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
using MediaBrowser.Model.Drawing;
using System.Globalization;
+using CommonIO;
namespace Emby.Drawing.ImageMagick
{
@@ -10,10 +12,12 @@ namespace Emby.Drawing.ImageMagick
private const int OffsetFromTopRightCorner = 38;
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public UnplayedCountIndicator(IApplicationPaths appPaths)
+ public UnplayedCountIndicator(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public void DrawUnplayedCountIndicator(MagickWand wand, ImageSize imageSize, int count)
@@ -33,7 +37,7 @@ namespace Emby.Drawing.ImageMagick
pixel.Opacity = 0;
pixel.Color = "white";
draw.FillColor = pixel;
- draw.Font = PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths);
+ draw.Font = PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths, _fileSystem);
draw.FontStyle = FontStyleType.NormalStyle;
draw.TextAlignment = TextAlignType.CenterAlign;
draw.FontWeight = FontWeightType.RegularStyle;
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 231bfa2b4..05d89406b 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -1,5 +1,4 @@
-using Emby.Drawing.Common;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
@@ -17,6 +16,9 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using Emby.Drawing.Common;
+using MediaBrowser.Controller.Library;
namespace Emby.Drawing
{
@@ -52,18 +54,20 @@ namespace Emby.Drawing
private readonly IServerApplicationPaths _appPaths;
private readonly IImageEncoder _imageEncoder;
private readonly SemaphoreSlim _imageProcessingSemaphore;
+ private readonly Func<ILibraryManager> _libraryManager;
public ImageProcessor(ILogger logger,
IServerApplicationPaths appPaths,
IFileSystem fileSystem,
IJsonSerializer jsonSerializer,
IImageEncoder imageEncoder,
- int maxConcurrentImageProcesses)
+ int maxConcurrentImageProcesses, Func<ILibraryManager> libraryManager)
{
_logger = logger;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
_imageEncoder = imageEncoder;
+ _libraryManager = libraryManager;
_appPaths = appPaths;
ImageEnhancers = new List<IImageEnhancer>();
@@ -106,6 +110,15 @@ namespace Emby.Drawing
}
}
+
+ public bool SupportsImageCollageCreation
+ {
+ get
+ {
+ return _imageEncoder.SupportsImageCollageCreation;
+ }
+ }
+
private string ResizedImageCachePath
{
get
@@ -157,7 +170,19 @@ namespace Emby.Drawing
throw new ArgumentNullException("options");
}
- var originalImagePath = options.Image.Path;
+ var originalImage = options.Image;
+
+ if (!originalImage.IsLocalFile)
+ {
+ originalImage = await _libraryManager().ConvertImageToLocal(options.Item, originalImage, options.ImageIndex).ConfigureAwait(false);
+ }
+
+ var originalImagePath = originalImage.Path;
+
+ if (!_imageEncoder.SupportsImageEncoding)
+ {
+ return originalImagePath;
+ }
if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace)
{
@@ -165,9 +190,9 @@ namespace Emby.Drawing
return originalImagePath;
}
- var dateModified = options.Image.DateModified;
+ var dateModified = originalImage.DateModified;
- if (options.CropWhiteSpace)
+ if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding)
{
var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
@@ -180,7 +205,7 @@ namespace Emby.Drawing
var tuple = await GetEnhancedImage(new ItemImageInfo
{
DateModified = dateModified,
- Type = options.Image.Type,
+ Type = originalImage.Type,
Path = originalImagePath
}, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false);
@@ -215,21 +240,18 @@ namespace Emby.Drawing
{
CheckDisposed();
- if (!File.Exists(cacheFilePath))
+ if (!_fileSystem.FileExists(cacheFilePath))
{
var newWidth = Convert.ToInt32(newSize.Width);
var newHeight = Convert.ToInt32(newSize.Height);
- Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
imageProcessingLockTaken = true;
_imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options);
-
- // ImageMagick doesn't seem to always release it right away
- await Task.Delay(100).ConfigureAwait(false);
}
}
finally
@@ -270,7 +292,7 @@ namespace Emby.Drawing
await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of contention
- if (File.Exists(croppedImagePath))
+ if (_fileSystem.FileExists(croppedImagePath))
{
semaphore.Release();
return GetResult(croppedImagePath);
@@ -280,13 +302,18 @@ namespace Emby.Drawing
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
imageProcessingLockTaken = true;
_imageEncoder.CropWhiteSpace(originalImagePath, croppedImagePath);
}
+ catch (NotImplementedException)
+ {
+ // No need to spam the log with an error message
+ return new Tuple<string, DateTime>(originalImagePath, dateModified);
+ }
catch (Exception ex)
{
// We have to have a catch-all here because some of the .net image methods throw a plain old Exception
@@ -359,19 +386,14 @@ namespace Emby.Drawing
return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
}
- /// <summary>
- /// Gets the size of the image.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>ImageSize.</returns>
- public ImageSize GetImageSize(string path)
+ public ImageSize GetImageSize(ItemImageInfo info)
{
- return GetImageSize(path, File.GetLastWriteTimeUtc(path), false);
+ return GetImageSize(info.Path, info.DateModified, false);
}
- public ImageSize GetImageSize(ItemImageInfo info)
+ public ImageSize GetImageSize(string path)
{
- return GetImageSize(info.Path, info.DateModified, false);
+ return GetImageSize(path, _fileSystem.GetLastWriteTimeUtc(path), false);
}
/// <summary>
@@ -399,7 +421,11 @@ namespace Emby.Drawing
{
size = GetImageSizeInternal(path, allowSlowMethod);
- _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
+ if (size.Width > 0 && size.Height > 0)
+ {
+ StartSaveImageSizeTimer();
+ _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
+ }
}
return size;
@@ -413,28 +439,26 @@ namespace Emby.Drawing
/// <returns>ImageSize.</returns>
private ImageSize GetImageSizeInternal(string path, bool allowSlowMethod)
{
- ImageSize size;
-
try
{
- size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
- }
- catch
- {
- if (!allowSlowMethod)
+ using (var file = TagLib.File.Create(path))
{
- throw;
- }
- //_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
+ var image = file as TagLib.Image.File;
- CheckDisposed();
+ var properties = image.Properties;
- size = _imageEncoder.GetImageSize(path);
+ return new ImageSize
+ {
+ Height = properties.PhotoHeight,
+ Width = properties.PhotoWidth
+ };
+ }
+ }
+ catch
+ {
}
- StartSaveImageSizeTimer();
-
- return size;
+ return ImageHeader.GetDimensions(path, _logger, _fileSystem);
}
private readonly Timer _saveImageSizeTimer;
@@ -452,7 +476,7 @@ namespace Emby.Drawing
try
{
var path = ImageSizeFile;
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
_jsonSerializer.SerializeToFile(_cachedImagedSizes, path);
}
catch (Exception ex)
@@ -624,7 +648,7 @@ namespace Emby.Drawing
await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of contention
- if (File.Exists(enhancedImagePath))
+ if (_fileSystem.FileExists(enhancedImagePath))
{
semaphore.Release();
return enhancedImagePath;
@@ -634,7 +658,7 @@ namespace Emby.Drawing
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
@@ -773,11 +797,11 @@ namespace Emby.Drawing
try
{
- _logger.Debug("Creating image collage and saving to {0}", options.OutputPath);
+ _logger.Info("Creating image collage and saving to {0}", options.OutputPath);
_imageEncoder.CreateImageCollage(options);
- _logger.Debug("Completed creation of image collage and saved to {0}", options.OutputPath);
+ _logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
}
finally
{
@@ -799,7 +823,6 @@ namespace Emby.Drawing
return false;
}
-
});
}
@@ -819,4 +842,4 @@ namespace Emby.Drawing
}
}
}
-}
+} \ No newline at end of file
diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs
new file mode 100644
index 000000000..30ea36329
--- /dev/null
+++ b/Emby.Drawing/NullImageEncoder.cs
@@ -0,0 +1,64 @@
+using System;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Drawing;
+
+namespace Emby.Drawing
+{
+ public class NullImageEncoder : IImageEncoder
+ {
+ public string[] SupportedInputFormats
+ {
+ get
+ {
+ return new[]
+ {
+ "png",
+ "jpeg",
+ "jpg"
+ };
+ }
+ }
+
+ public ImageFormat[] SupportedOutputFormats
+ {
+ get
+ {
+ return new[] { ImageFormat.Jpg, ImageFormat.Png };
+ }
+ }
+
+ public void CropWhiteSpace(string inputPath, string outputPath)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CreateImageCollage(ImageCollageOptions options)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string Name
+ {
+ get { return "Null Image Encoder"; }
+ }
+
+ public bool SupportsImageCollageCreation
+ {
+ get { return false; }
+ }
+
+ public bool SupportsImageEncoding
+ {
+ get { return false; }
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config
index acbd2ee3a..0fcdc278e 100644
--- a/Emby.Drawing/packages.config
+++ b/Emby.Drawing/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="ImageMagickSharp" version="1.0.0.16" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index c2b406190..7f4db5a89 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -15,6 +15,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api
{
@@ -95,7 +96,7 @@ namespace MediaBrowser.Api
{
var path = _config.ApplicationPaths.TranscodingTempPath;
- foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
+ foreach (var file in _fileSystem.GetFilePaths(path, true)
.ToList())
{
_fileSystem.DeleteFile(file);
@@ -567,7 +568,7 @@ namespace MediaBrowser.Api
var directory = Path.GetDirectoryName(outputFilePath);
var name = Path.GetFileNameWithoutExtension(outputFilePath);
- var filesToDelete = Directory.EnumerateFiles(directory)
+ var filesToDelete = _fileSystem.GetFilePaths(directory)
.Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)
.ToList();
@@ -577,7 +578,7 @@ namespace MediaBrowser.Api
{
try
{
- Logger.Info("Deleting HLS file {0}", file);
+ Logger.Debug("Deleting HLS file {0}", file);
_fileSystem.DeleteFile(file);
}
catch (DirectoryNotFoundException)
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
deleted file mode 100644
index 87084e415..000000000
--- a/MediaBrowser.Api/AppThemeService.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Themes;
-using MediaBrowser.Model.Themes;
-using ServiceStack;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Api
-{
- [Route("/Themes", "GET", Summary = "Gets a list of available themes for an app")]
- public class GetAppThemes : IReturn<List<AppThemeInfo>>
- {
- [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string App { get; set; }
- }
-
- [Route("/Themes/Info", "GET", Summary = "Gets an app theme")]
- public class GetAppTheme : IReturn<AppTheme>
- {
- [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string App { get; set; }
-
- [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string Name { get; set; }
- }
-
- [Route("/Themes/Images", "GET", Summary = "Gets an app theme")]
- public class GetAppThemeImage
- {
- [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string App { get; set; }
-
- [ApiMember(Name = "Theme", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string Theme { get; set; }
-
- [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string Name { get; set; }
-
- [ApiMember(Name = "CacheTag", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string CacheTag { get; set; }
- }
-
- [Route("/Themes", "POST", Summary = "Saves a theme")]
- public class SaveTheme : AppTheme, IReturnVoid
- {
- }
-
- [Authenticated]
- public class AppThemeService : BaseApiService
- {
- private readonly IAppThemeManager _themeManager;
- private readonly IFileSystem _fileSystem;
-
- public AppThemeService(IAppThemeManager themeManager, IFileSystem fileSystem)
- {
- _themeManager = themeManager;
- _fileSystem = fileSystem;
- }
-
- public object Get(GetAppThemes request)
- {
- var result = _themeManager.GetThemes(request.App).ToList();
-
- return ToOptimizedResult(result);
- }
-
- public object Get(GetAppTheme request)
- {
- var result = _themeManager.GetTheme(request.App, request.Name);
-
- return ToOptimizedResult(result);
- }
-
- public void Post(SaveTheme request)
- {
- _themeManager.SaveTheme(request);
- }
-
- public object Get(GetAppThemeImage request)
- {
- var info = _themeManager.GetImageImageInfo(request.App, request.Theme, request.Name);
-
- var cacheGuid = new Guid(info.CacheTag);
-
- TimeSpan? cacheDuration = null;
-
- if (!string.IsNullOrEmpty(request.CacheTag) && cacheGuid == new Guid(request.CacheTag))
- {
- cacheDuration = TimeSpan.FromDays(365);
- }
-
- var contentType = MimeTypes.GetMimeType(info.Path);
-
- return ResultFactory.GetCachedResult(Request, cacheGuid, null, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
- }
- }
-}
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index f266180a4..f33a30892 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -11,6 +11,7 @@ using ServiceStack.Web;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Api
{
diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs
index 4f5e2ab25..4e7b1a7d5 100644
--- a/MediaBrowser.Api/Dlna/DlnaServerService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs
@@ -108,7 +108,6 @@ namespace MediaBrowser.Api.Dlna
private readonly IConnectionManager _connectionManager;
private readonly IMediaReceiverRegistrar _mediaReceiverRegistrar;
- // TODO: Add utf-8
private const string XMLContentType = "text/xml; charset=UTF-8";
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IMediaReceiverRegistrar mediaReceiverRegistrar)
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index 457b4709b..3a31fc1d2 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@@ -8,6 +9,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Api
{
@@ -96,13 +98,14 @@ namespace MediaBrowser.Api
/// The _network manager
/// </summary>
private readonly INetworkManager _networkManager;
+ private IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="EnvironmentService" /> class.
/// </summary>
/// <param name="networkManager">The network manager.</param>
/// <exception cref="System.ArgumentNullException">networkManager</exception>
- public EnvironmentService(INetworkManager networkManager)
+ public EnvironmentService(INetworkManager networkManager, IFileSystem fileSystem)
{
if (networkManager == null)
{
@@ -110,6 +113,7 @@ namespace MediaBrowser.Api
}
_networkManager = networkManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -117,8 +121,6 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- /// <exception cref="System.ArgumentNullException">Path</exception>
- /// <exception cref="System.ArgumentException"></exception>
public object Get(GetDirectoryContents request)
{
var path = request.Path;
@@ -222,8 +224,7 @@ namespace MediaBrowser.Api
private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request)
{
// using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
- var entries = new DirectoryInfo(request.Path).EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
- .Concat<FileSystemInfo>(new DirectoryInfo(request.Path).EnumerateFiles("*", SearchOption.TopDirectoryOnly)).Where(i =>
+ var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i =>
{
if (!request.IncludeHidden && i.Attributes.HasFlag(FileAttributes.Hidden))
{
diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs
index b4d5a9949..1e0ca3438 100644
--- a/MediaBrowser.Api/Images/ImageByNameService.cs
+++ b/MediaBrowser.Api/Images/ImageByNameService.cs
@@ -9,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Api.Images
{
@@ -130,8 +131,7 @@ namespace MediaBrowser.Api.Images
{
try
{
- return new DirectoryInfo(path)
- .GetFiles("*", SearchOption.AllDirectories)
+ return _fileSystem.GetFiles(path)
.Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.Ordinal))
.Select(i => new ImageByNameInfo
{
@@ -184,7 +184,7 @@ namespace MediaBrowser.Api.Images
var paths = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(_appPaths.GeneralPath, request.Name, filename + i)).ToList();
- var path = paths.FirstOrDefault(File.Exists) ?? paths.FirstOrDefault();
+ var path = paths.FirstOrDefault(_fileSystem.FileExists) ?? paths.FirstOrDefault();
return ToStaticFileResult(path);
}
@@ -198,11 +198,11 @@ namespace MediaBrowser.Api.Images
{
var themeFolder = Path.Combine(_appPaths.RatingsPath, request.Theme);
- if (Directory.Exists(themeFolder))
+ if (_fileSystem.DirectoryExists(themeFolder))
{
var path = BaseItem.SupportedImageExtensions
.Select(i => Path.Combine(themeFolder, request.Name + i))
- .FirstOrDefault(File.Exists);
+ .FirstOrDefault(_fileSystem.FileExists);
if (!string.IsNullOrEmpty(path))
{
@@ -212,14 +212,14 @@ namespace MediaBrowser.Api.Images
var allFolder = Path.Combine(_appPaths.RatingsPath, "all");
- if (Directory.Exists(allFolder))
+ if (_fileSystem.DirectoryExists(allFolder))
{
// Avoid implicitly captured closure
var currentRequest = request;
var path = BaseItem.SupportedImageExtensions
.Select(i => Path.Combine(allFolder, currentRequest.Name + i))
- .FirstOrDefault(File.Exists);
+ .FirstOrDefault(_fileSystem.FileExists);
if (!string.IsNullOrEmpty(path))
{
@@ -239,10 +239,10 @@ namespace MediaBrowser.Api.Images
{
var themeFolder = Path.Combine(_appPaths.MediaInfoImagesPath, request.Theme);
- if (Directory.Exists(themeFolder))
+ if (_fileSystem.DirectoryExists(themeFolder))
{
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, request.Name + i))
- .FirstOrDefault(File.Exists);
+ .FirstOrDefault(_fileSystem.FileExists);
if (!string.IsNullOrEmpty(path))
{
@@ -252,13 +252,13 @@ namespace MediaBrowser.Api.Images
var allFolder = Path.Combine(_appPaths.MediaInfoImagesPath, "all");
- if (Directory.Exists(allFolder))
+ if (_fileSystem.DirectoryExists(allFolder))
{
// Avoid implicitly captured closure
var currentRequest = request;
var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, currentRequest.Name + i))
- .FirstOrDefault(File.Exists);
+ .FirstOrDefault(_fileSystem.FileExists);
if (!string.IsNullOrEmpty(path))
{
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index b8ea62137..259789fd1 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Images
@@ -311,17 +312,23 @@ namespace MediaBrowser.Api.Images
{
try
{
- var fileInfo = new FileInfo(info.Path);
-
int? width = null;
int? height = null;
+ long length = 0;
try
{
- var size = _imageProcessor.GetImageSize(info);
+ if (info.IsLocalFile)
+ {
+ var fileInfo = new FileInfo(info.Path);
+ length = fileInfo.Length;
+
+ var size = _imageProcessor.GetImageSize(info);
- width = Convert.ToInt32(size.Width);
- height = Convert.ToInt32(size.Height);
+ width = Convert.ToInt32(size.Width);
+ height = Convert.ToInt32(size.Height);
+
+ }
}
catch
{
@@ -333,7 +340,7 @@ namespace MediaBrowser.Api.Images
ImageIndex = imageIndex,
ImageType = info.Type,
ImageTag = _imageProcessor.GetImageCacheTag(item, info),
- Size = fileInfo.Length,
+ Size = length,
Width = width,
Height = height
};
@@ -557,7 +564,14 @@ namespace MediaBrowser.Api.Images
}).ToList() : new List<IImageEnhancer>();
- var format = GetOutputFormat(request, imageInfo, supportedImageEnhancers);
+ var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
+
+ if (request.CropWhitespace.HasValue)
+ {
+ cropwhitespace = request.CropWhitespace.Value;
+ }
+
+ var format = GetOutputFormat(request, imageInfo, cropwhitespace, supportedImageEnhancers);
var contentType = GetMimeType(format, imageInfo.Path);
var cacheGuid = new Guid(_imageProcessor.GetImageCacheTag(item, imageInfo, supportedImageEnhancers));
@@ -578,6 +592,7 @@ namespace MediaBrowser.Api.Images
return GetImageResult(item,
request,
imageInfo,
+ cropwhitespace,
format,
supportedImageEnhancers,
contentType,
@@ -590,6 +605,7 @@ namespace MediaBrowser.Api.Images
private async Task<object> GetImageResult(IHasImages item,
ImageRequest request,
ItemImageInfo image,
+ bool cropwhitespace,
ImageFormat format,
List<IImageEnhancer> enhancers,
string contentType,
@@ -597,13 +613,6 @@ namespace MediaBrowser.Api.Images
IDictionary<string, string> headers,
bool isHeadRequest)
{
- var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
-
- if (request.CropWhitespace.HasValue)
- {
- cropwhitespace = request.CropWhitespace.Value;
- }
-
var options = new ImageProcessingOptions
{
CropWhiteSpace = cropwhitespace,
@@ -637,7 +646,7 @@ namespace MediaBrowser.Api.Images
});
}
- private ImageFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, List<IImageEnhancer> enhancers)
+ private ImageFormat GetOutputFormat(ImageRequest request, ItemImageInfo image, bool cropwhitespace, List<IImageEnhancer> enhancers)
{
if (!string.IsNullOrWhiteSpace(request.Format))
{
@@ -648,10 +657,37 @@ namespace MediaBrowser.Api.Images
}
}
+ var extension = Path.GetExtension(image.Path);
+ ImageFormat? inputFormat = null;
+
+ if (string.Equals(extension, ".jpg", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase))
+ {
+ inputFormat = ImageFormat.Jpg;
+ }
+ else if (string.Equals(extension, ".png", StringComparison.OrdinalIgnoreCase))
+ {
+ inputFormat = ImageFormat.Png;
+ }
+
+ var clientSupportedFormats = GetClientSupportedFormats();
+ if (inputFormat.HasValue && clientSupportedFormats.Contains(inputFormat.Value) && enhancers.Count == 0)
+ {
+ if ((request.Quality ?? 100) == 100 && !request.Height.HasValue && !request.Width.HasValue &&
+ !request.AddPlayedIndicator && !request.PercentPlayed.HasValue && !request.UnplayedCount.HasValue && string.IsNullOrWhiteSpace(request.BackgroundColor))
+ {
+ // TODO: Allow this when specfying max width/height if the value is in range
+ if (!cropwhitespace && !request.MaxHeight.HasValue && !request.MaxWidth.HasValue)
+ {
+ return inputFormat.Value;
+ }
+ }
+ }
+
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
- if (serverFormats.Contains(ImageFormat.Webp) &&
- GetClientSupportedFormats().Contains(ImageFormat.Webp))
+ // Client doesn't care about format, so start with webp if supported
+ if (serverFormats.Contains(ImageFormat.Webp) && clientSupportedFormats.Contains(ImageFormat.Webp))
{
return ImageFormat.Webp;
}
@@ -661,10 +697,7 @@ namespace MediaBrowser.Api.Images
return ImageFormat.Png;
}
- var extension = Path.GetExtension(image.Path);
-
- if (string.Equals(extension, ".jpg", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase))
+ if (inputFormat.HasValue && inputFormat.Value == ImageFormat.Jpg)
{
return ImageFormat.Jpg;
}
@@ -675,7 +708,7 @@ namespace MediaBrowser.Api.Images
private ImageFormat[] GetClientSupportedFormats()
{
- var supportsWebP = (Request.AcceptTypes ?? new string[] {}).Contains("image/webp", StringComparer.OrdinalIgnoreCase);
+ var supportsWebP = (Request.AcceptTypes ?? new string[] { }).Contains("image/webp", StringComparer.OrdinalIgnoreCase);
var userAgent = Request.UserAgent ?? string.Empty;
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
index 6d2579ea9..9683632b2 100644
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ b/MediaBrowser.Api/Images/RemoteImageService.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Images
{
@@ -237,7 +238,7 @@ namespace MediaBrowser.Api.Images
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
- if (File.Exists(contentPath))
+ if (_fileSystem.FileExists(contentPath))
{
return ToStaticFileResult(contentPath);
}
@@ -281,7 +282,7 @@ namespace MediaBrowser.Api.Images
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
- Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(fullCachePath));
using (var stream = result.Content)
{
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
@@ -290,7 +291,7 @@ namespace MediaBrowser.Api.Images
}
}
- Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
using (var writer = new StreamWriter(pointerCachePath))
{
await writer.WriteAsync(fullCachePath).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index a0ba6e61f..f453036d7 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api
{
@@ -200,7 +201,7 @@ namespace MediaBrowser.Api
//}
item.ProviderIds = request.ProviderIds;
- var task = _providerManager.RefreshFullItem(item, new MetadataRefreshOptions
+ var task = _providerManager.RefreshFullItem(item, new MetadataRefreshOptions(_fileSystem)
{
MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
ImageRefreshMode = ImageRefreshMode.FullRefresh,
@@ -230,7 +231,7 @@ namespace MediaBrowser.Api
contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
}
- if (File.Exists(contentPath))
+ if (_fileSystem.FileExists(contentPath))
{
return ToStaticFileResult(contentPath);
}
@@ -271,7 +272,7 @@ namespace MediaBrowser.Api
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
- Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(fullCachePath));
using (var stream = result.Content)
{
using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
@@ -280,7 +281,7 @@ namespace MediaBrowser.Api
}
}
- Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
using (var writer = new StreamWriter(pointerCachePath))
{
await writer.WriteAsync(fullCachePath).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs
index f56fd3282..af1f1c90a 100644
--- a/MediaBrowser.Api/ItemRefreshService.cs
+++ b/MediaBrowser.Api/ItemRefreshService.cs
@@ -4,6 +4,8 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Providers;
using ServiceStack;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Api
{
@@ -37,11 +39,13 @@ namespace MediaBrowser.Api
{
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
+ private readonly IFileSystem _fileSystem;
- public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager)
+ public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_providerManager = providerManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -66,7 +70,7 @@ namespace MediaBrowser.Api
private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)
{
- return new MetadataRefreshOptions(new DirectoryService())
+ return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
MetadataRefreshMode = request.MetadataRefreshMode,
ImageRefreshMode = request.ImageRefreshMode,
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index b8ae9392a..23ff74495 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -211,11 +211,6 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- if (isLockedChanged && item.IsLocked)
- {
- item.IsUnidentified = false;
- }
-
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
if (request.People != null)
@@ -321,13 +316,8 @@ namespace MediaBrowser.Api
SetProductionLocations(item, request);
- var hasLang = item as IHasPreferredMetadataLanguage;
-
- if (hasLang != null)
- {
- hasLang.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
- hasLang.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
- }
+ item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
+ item.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
var hasDisplayOrder = item as IHasDisplayOrder;
if (hasDisplayOrder != null)
diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs
index 0ee28d6fe..111922bca 100644
--- a/MediaBrowser.Api/Library/LibraryHelpers.cs
+++ b/MediaBrowser.Api/Library/LibraryHelpers.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Api.Library
{
@@ -33,11 +34,11 @@ namespace MediaBrowser.Api.Library
var rootFolderPath = appPaths.DefaultUserViewsPath;
var path = Path.Combine(rootFolderPath, virtualFolderName);
- if (!Directory.Exists(path))
+ 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))
@@ -53,11 +54,9 @@ namespace MediaBrowser.Api.Library
/// <param name="virtualFolderName">Name of the virtual folder.</param>
/// <param name="path">The path.</param>
/// <param name="appPaths">The app paths.</param>
- /// <exception cref="System.IO.DirectoryNotFoundException">The path does not exist.</exception>
- /// <exception cref="System.ArgumentException">The path is not valid.</exception>
public static void AddMediaPath(IFileSystem fileSystem, string virtualFolderName, string path, IServerApplicationPaths appPaths)
{
- if (!Directory.Exists(path))
+ if (!fileSystem.DirectoryExists(path))
{
throw new DirectoryNotFoundException("The path does not exist.");
}
@@ -69,7 +68,7 @@ namespace MediaBrowser.Api.Library
var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
- while (File.Exists(lnk))
+ while (fileSystem.FileExists(lnk))
{
shortcutFilename += "1";
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 49dd121ba..319bc13fd 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -27,6 +27,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Api.Library
{
@@ -282,12 +284,13 @@ namespace MediaBrowser.Api.Library
private readonly IChannelManager _channelManager;
private readonly ITVSeriesManager _tvManager;
private readonly ILibraryMonitor _libraryMonitor;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary>
public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
- IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor)
+ IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem)
{
_itemRepo = itemRepo;
_libraryManager = libraryManager;
@@ -301,6 +304,7 @@ namespace MediaBrowser.Api.Library
_channelManager = channelManager;
_tvManager = tvManager;
_libraryMonitor = libraryMonitor;
+ _fileSystem = fileSystem;
}
public object Get(GetSimilarItems request)
@@ -557,7 +561,7 @@ namespace MediaBrowser.Api.Library
{
throw new ArgumentException("This command cannot be used for remote or virtual items.");
}
- if (Directory.Exists(item.Path))
+ if (_fileSystem.DirectoryExists(item.Path))
{
throw new ArgumentException("This command cannot be used for directories.");
}
@@ -719,7 +723,7 @@ namespace MediaBrowser.Api.Library
if (!item.CanDelete(user))
{
- throw new UnauthorizedAccessException();
+ throw new SecurityException("Unauthorized access");
}
if (item is ILiveTvRecording)
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index f5fe921ce..decd19602 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -10,6 +10,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Library
{
@@ -46,6 +47,12 @@ namespace MediaBrowser.Api.Library
/// </summary>
/// <value><c>true</c> if [refresh library]; otherwise, <c>false</c>.</value>
public bool RefreshLibrary { get; set; }
+
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string[] Paths { get; set; }
}
[Route("/Library/VirtualFolders", "DELETE")]
@@ -195,22 +202,42 @@ namespace MediaBrowser.Api.Library
var virtualFolderPath = Path.Combine(rootFolderPath, name);
- if (Directory.Exists(virtualFolderPath))
+ if (_fileSystem.DirectoryExists(virtualFolderPath))
{
- throw new ArgumentException("There is already a media collection with the name " + name + ".");
+ throw new ArgumentException("There is already a media library with the name " + 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
{
- Directory.CreateDirectory(virtualFolderPath);
+ _fileSystem.CreateDirectory(virtualFolderPath);
if (!string.IsNullOrEmpty(request.CollectionType))
{
var path = Path.Combine(virtualFolderPath, request.CollectionType + ".collection");
- File.Create(path);
+ using (File.Create(path))
+ {
+
+ }
+ }
+
+ if (request.Paths != null)
+ {
+ foreach (var path in request.Paths)
+ {
+ LibraryHelpers.AddMediaPath(_fileSystem, request.Name, path, _appPaths);
+ }
}
}
finally
@@ -256,12 +283,12 @@ namespace MediaBrowser.Api.Library
var currentPath = Path.Combine(rootFolderPath, request.Name);
var newPath = Path.Combine(rootFolderPath, request.NewName);
- if (!Directory.Exists(currentPath))
+ if (!_fileSystem.DirectoryExists(currentPath))
{
throw new DirectoryNotFoundException("The media collection does not exist");
}
- if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newPath))
+ if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath))
{
throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
}
@@ -276,11 +303,11 @@ namespace MediaBrowser.Api.Library
//Create an unique name
var temporaryName = Guid.NewGuid().ToString();
var temporaryPath = Path.Combine(rootFolderPath, temporaryName);
- Directory.Move(currentPath, temporaryPath);
+ _fileSystem.MoveDirectory(currentPath, temporaryPath);
currentPath = temporaryPath;
}
- Directory.Move(currentPath, newPath);
+ _fileSystem.MoveDirectory(currentPath, newPath);
}
finally
{
@@ -319,7 +346,7 @@ namespace MediaBrowser.Api.Library
var path = Path.Combine(rootFolderPath, request.Name);
- if (!Directory.Exists(path))
+ if (!_fileSystem.DirectoryExists(path))
{
throw new DirectoryNotFoundException("The media folder does not exist");
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 07e64c98d..344d6ab3d 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -521,12 +521,12 @@ namespace MediaBrowser.Api.LiveTv
if (user == null)
{
- throw new UnauthorizedAccessException("Anonymous live tv management is not allowed.");
+ throw new SecurityException("Anonymous live tv management is not allowed.");
}
if (!user.Policy.EnableLiveTvManagement)
{
- throw new UnauthorizedAccessException("The current user does not have permission to manage live tv.");
+ throw new SecurityException("The current user does not have permission to manage live tv.");
}
}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 295cc78e9..7be644bc8 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -11,10 +11,9 @@
<AssemblyName>MediaBrowser.Api</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
+ <ReleaseVersion>
+ </ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -25,7 +24,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -34,7 +32,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
<DebugType>none</DebugType>
@@ -43,15 +40,17 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
- <Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -64,12 +63,14 @@
<Reference Include="ServiceStack.Text">
<HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
</Reference>
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
- <Compile Include="AppThemeService.cs" />
<Compile Include="BrandingService.cs" />
<Compile Include="ChannelService.cs" />
<Compile Include="ConnectService.cs" />
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 531d67eed..36207c8b4 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -23,6 +23,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Playback
{
@@ -290,13 +291,6 @@ namespace MediaBrowser.Api.Playback
{
get
{
- var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder;
-
- if (!string.IsNullOrWhiteSpace(lib))
- {
- return lib;
- }
-
return "libx264";
}
}
@@ -810,13 +804,53 @@ namespace MediaBrowser.Api.Playback
}
/// <summary>
+ /// Gets the name of the output video codec
+ /// </summary>
+ /// <param name="state">The state.</param>
+ /// <returns>System.String.</returns>
+ protected string GetVideoDecoder(StreamState state)
+ {
+ if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareVideoDecoder, "qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ {
+ switch (state.MediaSource.VideoStream.Codec.ToLower())
+ {
+ case "avc":
+ case "h264":
+ if (MediaEncoder.SupportsDecoder("h264_qsv"))
+ {
+ return "-c:v h264_qsv ";
+ }
+ break;
+ case "mpeg2video":
+ if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
+ {
+ return "-c:v mpeg2_qsv ";
+ }
+ break;
+ case "vc1":
+ if (MediaEncoder.SupportsDecoder("vc1_qsv"))
+ {
+ return "-c:v vc1_qsv ";
+ }
+ break;
+ }
+ }
+ }
+
+ // leave blank so ffmpeg will decide
+ return null;
+ }
+
+ /// <summary>
/// Gets the input argument.
/// </summary>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
protected string GetInputArgument(StreamState state)
{
- var arg = "-i " + GetInputPathArgument(state);
+ var arg = string.Format("-i {0}", GetInputPathArgument(state));
if (state.SubtitleStream != null)
{
@@ -826,7 +860,7 @@ namespace MediaBrowser.Api.Playback
}
}
- return arg;
+ return arg.Trim();
}
private string GetInputPathArgument(StreamState state)
@@ -840,7 +874,7 @@ namespace MediaBrowser.Api.Playback
{
if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
{
- inputPath = MediaEncoderHelpers.GetInputArgument(mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
+ inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
}
}
@@ -889,7 +923,7 @@ namespace MediaBrowser.Api.Playback
CancellationTokenSource cancellationTokenSource,
string workingDirectory = null)
{
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
@@ -942,7 +976,7 @@ namespace MediaBrowser.Api.Playback
Logger.Info(commandLineLogMessage);
var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath));
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
@@ -972,7 +1006,7 @@ namespace MediaBrowser.Api.Playback
StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
// Wait for the file to exist before proceeeding
- while (!File.Exists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
+ while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
{
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
@@ -1027,6 +1061,7 @@ namespace MediaBrowser.Api.Playback
var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await target.FlushAsync().ConfigureAwait(false);
}
}
}
@@ -1151,15 +1186,8 @@ namespace MediaBrowser.Api.Playback
if (bitrate.HasValue)
{
- var hasFixedResolution = state.VideoRequest.HasFixedResolution;
-
if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase))
{
- if (hasFixedResolution)
- {
- return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture));
- }
-
// With vpx when crf is used, b:v becomes a max rate
// https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up.
return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture));
@@ -1170,36 +1198,15 @@ namespace MediaBrowser.Api.Playback
return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
- // h264_qsv
- if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase))
+ // h264
+ if (isHls)
{
- if (hasFixedResolution)
- {
- if (isHls)
- {
- return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -b:v {0} -maxrate ({0}*1.2) -bufsize ({0}*2)", bitrate.Value.ToString(UsCulture));
+ return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
+ bitrate.Value.ToString(UsCulture),
+ (bitrate.Value * 2).ToString(UsCulture));
}
- // H264
- if (hasFixedResolution)
- {
- if (isHls)
- {
- return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
- }
-
- return string.Format(" -maxrate {0} -bufsize {1}",
- bitrate.Value.ToString(UsCulture),
- (bitrate.Value * 2).ToString(UsCulture));
+ return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
}
return string.Empty;
@@ -1986,7 +1993,8 @@ namespace MediaBrowser.Api.Playback
state.IsTargetCabac,
state.TargetRefFrames,
state.TargetVideoStreamCount,
- state.TargetAudioStreamCount);
+ state.TargetAudioStreamCount,
+ state.TargetVideoCodecTag);
if (mediaProfile != null)
{
@@ -2083,7 +2091,8 @@ namespace MediaBrowser.Api.Playback
state.IsTargetCabac,
state.TargetRefFrames,
state.TargetVideoStreamCount,
- state.TargetAudioStreamCount
+ state.TargetAudioStreamCount,
+ state.TargetVideoCodecTag
).FirstOrDefault() ?? string.Empty;
}
@@ -2158,6 +2167,12 @@ namespace MediaBrowser.Api.Playback
inputModifier += " -re";
}
+ var videoDecoder = GetVideoDecoder(state);
+ if (!string.IsNullOrWhiteSpace(videoDecoder))
+ {
+ inputModifier += " " + videoDecoder;
+ }
+
return inputModifier;
}
diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
index c201ffd58..49d3db110 100644
--- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Dash
@@ -174,7 +175,7 @@ namespace MediaBrowser.Api.Playback.Dash
var workingDirectory = Path.Combine(Path.GetDirectoryName(playlistPath), (startNumber == -1 ? 0 : startNumber).ToString(CultureInfo.InvariantCulture));
state.WaitForPath = Path.Combine(workingDirectory, Path.GetFileName(playlistPath));
- Directory.CreateDirectory(workingDirectory);
+ FileSystem.CreateDirectory(workingDirectory);
job = await StartFfMpeg(state, playlistPath, cancellationTokenSource, workingDirectory).ConfigureAwait(false);
await WaitForMinimumDashSegmentCount(Path.Combine(workingDirectory, Path.GetFileName(playlistPath)), 1, cancellationTokenSource.Token).ConfigureAwait(false);
}
@@ -322,14 +323,13 @@ namespace MediaBrowser.Api.Playback.Dash
}
}
- private static List<FileInfo> GetLastTranscodingFiles(string playlist, string segmentExtension, IFileSystem fileSystem, int count)
+ private static List<FileSystemMetadata> GetLastTranscodingFiles(string playlist, string segmentExtension, IFileSystem fileSystem, int count)
{
var folder = Path.GetDirectoryName(playlist);
try
{
- return new DirectoryInfo(folder)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ return fileSystem.GetFiles(folder)
.Where(i => string.Equals(i.Extension, segmentExtension, StringComparison.OrdinalIgnoreCase))
.OrderByDescending(fileSystem.GetLastWriteTimeUtc)
.Take(count)
@@ -337,7 +337,7 @@ namespace MediaBrowser.Api.Playback.Dash
}
catch (DirectoryNotFoundException)
{
- return new List<FileInfo>();
+ return new List<FileSystemMetadata>();
}
}
@@ -348,20 +348,20 @@ namespace MediaBrowser.Api.Playback.Dash
if (requestedIndex == -1)
{
var path = Path.Combine(folder, "0", "stream" + representationId + "-" + "init" + segmentExtension);
- return File.Exists(path) ? path : null;
+ return FileSystem.FileExists(path) ? path : null;
}
try
{
- foreach (var subfolder in new DirectoryInfo(folder).EnumerateDirectories().ToList())
+ foreach (var subfolder in FileSystem.GetDirectoryPaths(folder).ToList())
{
- var subfolderName = Path.GetFileNameWithoutExtension(subfolder.FullName);
+ var subfolderName = Path.GetFileNameWithoutExtension(subfolder);
int startNumber;
if (int.TryParse(subfolderName, NumberStyles.Any, UsCulture, out startNumber))
{
var segmentIndex = requestedIndex - startNumber + 1;
var path = Path.Combine(folder, subfolderName, "stream" + representationId + "-" + segmentIndex.ToString("00000", CultureInfo.InvariantCulture) + segmentExtension);
- if (File.Exists(path))
+ if (FileSystem.FileExists(path))
{
return path;
}
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index e4f00e2a0..60412159c 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -15,6 +15,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Hls
{
@@ -23,7 +24,8 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public abstract class BaseHlsService : BaseStreamingService
{
- protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
+ protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
{
}
@@ -90,12 +92,12 @@ namespace MediaBrowser.Api.Playback.Hls
TranscodingJob job = null;
var playlist = state.OutputFilePath;
- if (!File.Exists(playlist))
+ if (!FileSystem.FileExists(playlist))
{
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try
{
- if (!File.Exists(playlist))
+ if (!FileSystem.FileExists(playlist))
{
// If the playlist doesn't already exist, startup ffmpeg
try
@@ -150,7 +152,7 @@ namespace MediaBrowser.Api.Playback.Hls
{
ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
}
-
+
return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
}
@@ -317,4 +319,4 @@ namespace MediaBrowser.Api.Playback.Hls
return false;
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 7b2844cd4..6ca2677e7 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Api.Playback.Hls
@@ -165,7 +166,7 @@ namespace MediaBrowser.Api.Playback.Hls
TranscodingJob job = null;
- if (File.Exists(segmentPath))
+ if (FileSystem.FileExists(segmentPath))
{
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
@@ -174,7 +175,7 @@ namespace MediaBrowser.Api.Playback.Hls
await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try
{
- if (File.Exists(segmentPath))
+ if (FileSystem.FileExists(segmentPath))
{
job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false);
@@ -354,7 +355,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
}
- private void DeleteFile(FileInfo file, int retryCount)
+ private void DeleteFile(FileSystemMetadata file, int retryCount)
{
if (retryCount >= 5)
{
@@ -378,7 +379,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
}
- private static FileInfo GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
+ private static FileSystemMetadata GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
{
var folder = Path.GetDirectoryName(playlist);
@@ -386,8 +387,7 @@ namespace MediaBrowser.Api.Playback.Hls
try
{
- return new DirectoryInfo(folder)
- .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ return fileSystem.GetFiles(folder)
.Where(i => string.Equals(i.Extension, segmentExtension, StringComparison.OrdinalIgnoreCase) && Path.GetFileNameWithoutExtension(i.Name).StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase))
.OrderByDescending(fileSystem.GetLastWriteTimeUtc)
.FirstOrDefault();
@@ -432,7 +432,7 @@ namespace MediaBrowser.Api.Playback.Hls
CancellationToken cancellationToken)
{
// If all transcoding has completed, just return immediately
- if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath))
+ if (transcodingJob != null && transcodingJob.HasExited && FileSystem.FileExists(segmentPath))
{
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
}
@@ -452,7 +452,7 @@ namespace MediaBrowser.Api.Playback.Hls
// If it appears in the playlist, it's done
if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
{
- if (File.Exists(segmentPath))
+ if (FileSystem.FileExists(segmentPath))
{
return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob);
}
@@ -989,4 +989,4 @@ namespace MediaBrowser.Api.Playback.Hls
return base.CanStreamCopyVideo(request, videoStream);
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 2d1abf7e9..c5392b38f 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using System;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Hls
{
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 0b7b50134..2ab2d11f6 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.Api.Playback
Size = 102400;
}
}
-
+
[Authenticated]
public class MediaInfoService : BaseApiService
{
@@ -289,7 +289,7 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsDirectStream)
{
options.MaxBitrate = GetMaxBitrate(maxBitrate);
-
+
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
streamBuilder.BuildAudioItem(options) :
@@ -309,7 +309,7 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsTranscoding)
{
options.MaxBitrate = GetMaxBitrate(maxBitrate);
-
+
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
streamBuilder.BuildAudioItem(options) :
@@ -336,9 +336,15 @@ namespace MediaBrowser.Api.Playback
var maxBitrate = clientMaxBitrate;
var remoteClientMaxBitrate = _config.Configuration.RemoteClientBitrateLimit;
- if (remoteClientMaxBitrate > 0 && !_networkManager.IsInLocalNetwork(Request.RemoteIp))
+ if (remoteClientMaxBitrate > 0)
{
- maxBitrate = Math.Min(maxBitrate ?? remoteClientMaxBitrate, remoteClientMaxBitrate);
+ var isInLocalNetwork = _networkManager.IsInLocalNetwork(Request.RemoteIp);
+
+ Logger.Info("RemoteClientBitrateLimit: {0}, RemoteIp: {1}, IsInLocalNetwork: {2}", remoteClientMaxBitrate, Request.RemoteIp, isInLocalNetwork);
+ if (!isInLocalNetwork)
+ {
+ maxBitrate = Math.Min(maxBitrate ?? remoteClientMaxBitrate, remoteClientMaxBitrate);
+ }
}
return maxBitrate;
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 67a9cab58..ada4761c7 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -11,6 +11,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
{
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 910ac18e7..61c3e9aa8 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -17,6 +17,7 @@ using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
{
@@ -139,7 +140,7 @@ namespace MediaBrowser.Api.Playback.Progressive
}
var outputPath = state.OutputFilePath;
- var outputPathExists = File.Exists(outputPath);
+ var outputPathExists = FileSystem.FileExists(outputPath);
var isTranscodeCached = outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive);
@@ -325,7 +326,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
TranscodingJob job;
- if (!File.Exists(outputPath))
+ if (!FileSystem.FileExists(outputPath))
{
job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index adedd9461..2719b1faf 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
{
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 84ae26248..d79040dd4 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -11,12 +11,14 @@ using MediaBrowser.Model.Serialization;
using ServiceStack;
using System;
using System.IO;
+using CommonIO;
namespace MediaBrowser.Api.Playback.Progressive
{
/// <summary>
/// Class GetVideoStream
/// </summary>
+ [Route("/Videos/{Id}/stream.mpegts", "GET")]
[Route("/Videos/{Id}/stream.ts", "GET")]
[Route("/Videos/{Id}/stream.webm", "GET")]
[Route("/Videos/{Id}/stream.asf", "GET")]
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 34dc5ea12..d61bb9c0f 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -74,7 +74,7 @@ namespace MediaBrowser.Api.Playback
{
get
{
- return ReadInputAtNativeFramerate ? 1000 : 0;
+ return 0;
}
}
@@ -457,6 +457,17 @@ namespace MediaBrowser.Api.Playback
}
}
+ public string TargetVideoCodecTag
+ {
+ get
+ {
+ var stream = VideoStream;
+ return !Request.Static
+ ? null
+ : stream == null ? null : stream.CodecTag;
+ }
+ }
+
public bool? IsTargetAnamorphic
{
get
diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs
index e16ca1ee8..3dafd0eeb 100644
--- a/MediaBrowser.Api/PlaylistService.cs
+++ b/MediaBrowser.Api/PlaylistService.cs
@@ -40,10 +40,27 @@ namespace MediaBrowser.Api
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string UserId { get; set; }
}
+ [Route("/Playlists/{Id}/Items/{ItemId}/Move/{NewIndex}", "POST", Summary = "Moves a playlist item")]
+ public class MoveItem : IReturnVoid
+ {
+ [ApiMember(Name = "ItemId", Description = "ItemId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string ItemId { get; set; }
+
+ [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "NewIndex", Description = "NewIndex", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public int NewIndex { get; set; }
+ }
+
[Route("/Playlists/{Id}/Items", "DELETE", Summary = "Removes items from a playlist")]
public class RemoveFromPlaylist : IReturnVoid
{
@@ -105,6 +122,13 @@ namespace MediaBrowser.Api
_libraryManager = libraryManager;
}
+ public void Post(MoveItem request)
+ {
+ var task = _playlistManager.MoveItem(request.Id, request.ItemId, request.NewIndex);
+
+ Task.WaitAll(task);
+ }
+
public async Task<object> Post(CreatePlaylist request)
{
var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
index eb49914eb..a7fd14bf0 100644
--- a/MediaBrowser.Api/PluginService.cs
+++ b/MediaBrowser.Api/PluginService.cs
@@ -118,6 +118,14 @@ namespace MediaBrowser.Api
public string Name { get; set; }
}
+ [Route("/Appstore/Register", "POST", Summary = "Registers an appstore sale")]
+ [Authenticated]
+ public class RegisterAppstoreSale
+ {
+ [ApiMember(Name = "Parameters", Description = "Java representation of parameters to pass through to admin server", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string Parameters { get; set; }
+ }
+
/// <summary>
/// Class PluginsService
/// </summary>
@@ -266,6 +274,16 @@ namespace MediaBrowser.Api
}
/// <summary>
+ /// Post app store sale
+ /// </summary>
+ /// <param name="request"></param>
+ /// <returns></returns>
+ public async Task Post(RegisterAppstoreSale request)
+ {
+ await _securityManager.RegisterAppStoreSale(request.Parameters);
+ }
+
+ /// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
diff --git a/MediaBrowser.Api/Reports/Common/HeaderMetadata.cs b/MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
index af5abf46a..62f941a7a 100644
--- a/MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
+++ b/MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
@@ -43,7 +43,6 @@ namespace MediaBrowser.Api.Reports
MusicArtist,
AudioAlbum,
Locked,
- Unidentified,
ImagePrimary,
ImageBackdrop,
ImageLogo,
diff --git a/MediaBrowser.Api/Reports/Common/ItemViewType.cs b/MediaBrowser.Api/Reports/Common/ItemViewType.cs
index 5126457cf..098442115 100644
--- a/MediaBrowser.Api/Reports/Common/ItemViewType.cs
+++ b/MediaBrowser.Api/Reports/Common/ItemViewType.cs
@@ -17,7 +17,6 @@ namespace MediaBrowser.Api.Reports
TrailersImage,
SpecialsImage,
LockDataImage,
- UnidentifiedImage,
TagsPrimaryImage,
TagsBackdropImage,
TagsLogoImage,
diff --git a/MediaBrowser.Api/Reports/Data/ReportBuilder.cs b/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
index 512441bd7..5e339dc73 100644
--- a/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
+++ b/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
@@ -105,7 +105,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -122,7 +121,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -143,7 +141,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -161,7 +158,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -177,7 +173,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -198,7 +193,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -223,7 +217,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -241,7 +234,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -260,7 +252,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -284,7 +275,6 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -315,11 +305,9 @@ namespace MediaBrowser.Api.Reports
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
- HeaderMetadata.Unidentified,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
@@ -376,12 +364,6 @@ namespace MediaBrowser.Api.Reports
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Export;
break;
- case HeaderMetadata.Unidentified:
- option.Column = (i, r) => this.GetBoolString(r.IsUnidentified);
- option.Header.ItemViewType = ItemViewType.UnidentifiedImage;
- option.Header.CanGroup = false;
- option.Header.DisplayType = ReportDisplayType.Export;
- break;
case HeaderMetadata.ImagePrimary:
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsPrimary);
option.Header.ItemViewType = ItemViewType.TagsPrimaryImage;
@@ -633,7 +615,6 @@ namespace MediaBrowser.Api.Reports
{
Id = item.Id.ToString("N"),
HasLockData = item.IsLocked,
- IsUnidentified = item.IsUnidentified,
HasLocalTrailer = hasTrailers != null ? hasTrailers.GetTrailerIds().Count() > 0 : false,
HasImageTagsPrimary = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Primary) > 0),
HasImageTagsBackdrop = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Backdrop) > 0),
diff --git a/MediaBrowser.Api/Reports/Model/ReportRow.cs b/MediaBrowser.Api/Reports/Model/ReportRow.cs
index 3f66b8479..1a46b72b7 100644
--- a/MediaBrowser.Api/Reports/Model/ReportRow.cs
+++ b/MediaBrowser.Api/Reports/Model/ReportRow.cs
@@ -56,10 +56,6 @@ namespace MediaBrowser.Api.Reports
/// <value> true if this object has specials, false if not. </value>
public bool HasSpecials { get; set; }
- /// <summary> Gets or sets a value indicating whether this object is unidentified. </summary>
- /// <value> true if this object is unidentified, false if not. </value>
- public bool IsUnidentified { get; set; }
-
/// <summary> Gets or sets the columns. </summary>
/// <value> The columns. </value>
public List<ReportItem> Columns { get; set; }
diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs
index 82e7264f1..6c2886f5b 100644
--- a/MediaBrowser.Api/Reports/ReportsService.cs
+++ b/MediaBrowser.Api/Reports/ReportsService.cs
@@ -226,7 +226,6 @@ namespace MediaBrowser.Api.Reports
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
IsYearMismatched = request.IsYearMismatched,
- IsUnidentified = request.IsUnidentified,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,
diff --git a/MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs b/MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
index c9ee6337f..fb694d6e1 100644
--- a/MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
+++ b/MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
@@ -213,7 +213,7 @@ namespace MediaBrowser.Api.Reports
};
foreach (var item in t)
{
- var ps = items.Where(x => x.People != null && x.SupportsPeople).SelectMany(x => x.People)
+ var ps = items.SelectMany(x => _libraryManager.GetPeople(x))
.Where(n => n.Type == item.ToString())
.GroupBy(x => x.Name)
.OrderByDescending(x => x.Count())
diff --git a/MediaBrowser.Api/Social/SharingService.cs b/MediaBrowser.Api/Social/SharingService.cs
index 608008455..7d61c24ec 100644
--- a/MediaBrowser.Api/Social/SharingService.cs
+++ b/MediaBrowser.Api/Social/SharingService.cs
@@ -124,7 +124,7 @@ namespace MediaBrowser.Api.Social
Task.WaitAll(task);
}
- public object Get(GetShareImage request)
+ public async Task<object> Get(GetShareImage request)
{
var share = _sharingManager.GetShareInfo(request.Id);
@@ -143,7 +143,21 @@ namespace MediaBrowser.Api.Social
if (image != null)
{
- return ToStaticFileResult(image.Path);
+ if (image.IsLocalFile)
+ {
+ return ToStaticFileResult(image.Path);
+ }
+
+ try
+ {
+ // Don't fail the request over this
+ var updatedImage = await _libraryManager.ConvertImageToLocal(item, image, 0).ConfigureAwait(false);
+ return ToStaticFileResult(updatedImage.Path);
+ }
+ catch
+ {
+
+ }
}
// Grab a dlna icon if nothing else is available
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index e9ac45fa2..399c81ae8 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -69,10 +69,11 @@ namespace MediaBrowser.Api
_config.Configuration.MergeMetadataAndImagesByName = true;
_config.Configuration.EnableStandaloneMetadata = true;
_config.Configuration.EnableLibraryMetadataSubFolder = true;
- _config.Configuration.EnableUserSpecificUserViews = true;
_config.Configuration.EnableCustomPathSubFolders = true;
_config.Configuration.DisableXmlSavers = true;
_config.Configuration.DisableStartupScan = true;
+ _config.Configuration.EnableUserViews = true;
+ _config.Configuration.EnableDateLastRefresh = true;
_config.SaveConfiguration();
}
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index c9280b6f6..37034751d 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -15,7 +15,9 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Api.Subtitles
{
@@ -127,14 +129,16 @@ namespace MediaBrowser.Api.Subtitles
private readonly ISubtitleEncoder _subtitleEncoder;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IProviderManager _providerManager;
+ private readonly IFileSystem _fileSystem;
- public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProviderManager providerManager)
+ public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProviderManager providerManager, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_subtitleManager = subtitleManager;
_subtitleEncoder = subtitleEncoder;
_mediaSourceManager = mediaSourceManager;
_providerManager = providerManager;
+ _fileSystem = fileSystem;
}
public async Task<object> Get(GetSubtitlePlaylist request)
@@ -259,7 +263,7 @@ namespace MediaBrowser.Api.Subtitles
await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
.ConfigureAwait(false);
- _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(_fileSystem));
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index 5863e05e3..593c3a108 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -244,7 +244,15 @@ namespace MediaBrowser.Api.Sync
var task = _syncManager.ReportSyncJobItemTransferBeginning(request.Id);
Task.WaitAll(task);
- return ToStaticFileResult(jobItem.OutputPath);
+ return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ {
+ Path = jobItem.OutputPath,
+ OnError = () =>
+ {
+ var failedTask = _syncManager.ReportSyncJobItemTransferFailed(request.Id);
+ Task.WaitAll(failedTask);
+ }
+ });
}
public object Get(GetSyncDialogOptions request)
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index aa1226901..a95fcb542 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api.System
{
@@ -118,18 +119,17 @@ namespace MediaBrowser.Api.System
public object Get(GetServerLogs request)
{
- List<FileInfo> files;
+ List<FileSystemMetadata> files;
try
{
- files = new DirectoryInfo(_appPaths.LogDirectoryPath)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.Where(i => string.Equals(i.Extension, ".txt", StringComparison.OrdinalIgnoreCase))
.ToList();
}
catch (DirectoryNotFoundException)
{
- files = new List<FileInfo>();
+ files = new List<FileSystemMetadata>();
}
var result = files.Select(i => new LogFile
@@ -149,8 +149,7 @@ namespace MediaBrowser.Api.System
public object Get(GetLogFile request)
{
- var file = new DirectoryInfo(_appPaths.LogDirectoryPath)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite);
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index 7db8e4dca..4d844e6cb 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -299,9 +299,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "IsLocked", Description = "Optional filter by items that are locked.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public bool? IsLocked { get; set; }
- [ApiMember(Name = "IsUnidentified", Description = "Optional filter by items that are unidentified by internet metadata providers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public bool? IsUnidentified { get; set; }
-
[ApiMember(Name = "IsPlaceHolder", Description = "Optional filter by items that are placeholders", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public bool? IsPlaceHolder { get; set; }
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 7d3290c2f..f1168ab7f 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -192,7 +192,6 @@ namespace MediaBrowser.Api.UserLibrary
NameStartsWithOrGreater = request.NameStartsWithOrGreater,
HasImdbId = request.HasImdbId,
IsYearMismatched = request.IsYearMismatched,
- IsUnidentified = request.IsUnidentified,
IsPlaceHolder = request.IsPlaceHolder,
IsLocked = request.IsLocked,
IsInBoxSet = request.IsInBoxSet,
diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
index a49ab8556..9d7c38d6f 100644
--- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
@@ -39,6 +39,17 @@ namespace MediaBrowser.Api.UserLibrary
public string UserId { get; set; }
}
+ [Route("/Users/{UserId}/GroupingOptions", "GET")]
+ public class GetGroupingOptions : IReturn<List<SpecialViewOption>>
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string UserId { get; set; }
+ }
+
public class UserViewsService : BaseApiService
{
private readonly IUserManager _userManager;
@@ -105,6 +116,29 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(list);
}
+ public async Task<object> Get(GetGroupingOptions request)
+ {
+ var user = _userManager.GetUserById(request.UserId);
+
+ var views = user.RootFolder
+ .GetChildren(user, true)
+ .OfType<Folder>()
+ .Where(i => !UserView.IsExcludedFromGrouping(i))
+ .ToList();
+
+ var list = views
+ .Select(i => new SpecialViewOption
+ {
+ Name = i.Name,
+ Id = i.Id.ToString("N")
+
+ })
+ .OrderBy(i => i.Name)
+ .ToList();
+
+ return ToOptimizedResult(list);
+ }
+
private bool IsEligibleForSpecialView(ICollectionFolder view)
{
var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos };
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index a65bee7ef..0cffbb42c 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -11,6 +11,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Api
{
diff --git a/MediaBrowser.Api/packages.config b/MediaBrowser.Api/packages.config
index 6df166204..d96012318 100644
--- a/MediaBrowser.Api/packages.config
+++ b/MediaBrowser.Api/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="morelinq" version="1.1.0" targetFramework="net45" />
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
+ <package id="morelinq" version="1.1.1" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
index cdcbc311a..0009c7193 100644
--- a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
+++ b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
@@ -7,6 +7,8 @@ using SharpCompress.Reader;
using SharpCompress.Reader.Zip;
using System;
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Common.Implementations.Archiving
{
@@ -15,7 +17,14 @@ namespace MediaBrowser.Common.Implementations.Archiving
/// </summary>
public class ZipClient : IZipClient
{
- /// <summary>
+ private IFileSystem _fileSystem;
+
+ public ZipClient(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
+ /// <summary>
/// Extracts all.
/// </summary>
/// <param name="sourceFile">The source file.</param>
@@ -23,7 +32,7 @@ namespace MediaBrowser.Common.Implementations.Archiving
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
public void ExtractAll(string sourceFile, string targetPath, bool overwriteExistingFiles)
{
- using (var fileStream = File.OpenRead(sourceFile))
+ using (var fileStream = _fileSystem.OpenRead(sourceFile))
{
ExtractAll(fileStream, targetPath, overwriteExistingFiles);
}
@@ -73,7 +82,7 @@ namespace MediaBrowser.Common.Implementations.Archiving
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
public void ExtractAllFrom7z(string sourceFile, string targetPath, bool overwriteExistingFiles)
{
- using (var fileStream = File.OpenRead(sourceFile))
+ using (var fileStream = _fileSystem.OpenRead(sourceFile))
{
ExtractAllFrom7z(fileStream, targetPath, overwriteExistingFiles);
}
@@ -112,7 +121,7 @@ namespace MediaBrowser.Common.Implementations.Archiving
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
public void ExtractAllFromTar(string sourceFile, string targetPath, bool overwriteExistingFiles)
{
- using (var fileStream = File.OpenRead(sourceFile))
+ using (var fileStream = _fileSystem.OpenRead(sourceFile))
{
ExtractAllFromTar(fileStream, targetPath, overwriteExistingFiles);
}
@@ -150,7 +159,7 @@ namespace MediaBrowser.Common.Implementations.Archiving
/// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param>
public void ExtractAllFromRar(string sourceFile, string targetPath, bool overwriteExistingFiles)
{
- using (var fileStream = File.OpenRead(sourceFile))
+ using (var fileStream = _fileSystem.OpenRead(sourceFile))
{
ExtractAllFromRar(fileStream, targetPath, overwriteExistingFiles);
}
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index 70ed5c319..6dc97100d 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -30,6 +30,7 @@ using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations
{
@@ -93,7 +94,7 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// The _XML serializer
/// </summary>
- protected readonly IXmlSerializer XmlSerializer = new XmlSerializer();
+ protected readonly IXmlSerializer XmlSerializer;
/// <summary>
/// Gets assemblies that failed to load
@@ -180,7 +181,7 @@ namespace MediaBrowser.Common.Implementations
{
if (_deviceId == null)
{
- _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"));
+ _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
}
return _deviceId.Value;
@@ -199,6 +200,7 @@ namespace MediaBrowser.Common.Implementations
ILogManager logManager,
IFileSystem fileSystem)
{
+ XmlSerializer = new MediaBrowser.Common.Implementations.Serialization.XmlSerializer (fileSystem);
FailedAssemblies = new List<string>();
ApplicationPaths = applicationPaths;
@@ -320,7 +322,7 @@ namespace MediaBrowser.Common.Implementations
protected virtual IJsonSerializer CreateJsonSerializer()
{
- return new JsonSerializer();
+ return new JsonSerializer(FileSystemManager);
}
private void SetHttpLimit()
@@ -414,6 +416,8 @@ namespace MediaBrowser.Common.Implementations
/// </summary>
protected virtual void FindParts()
{
+ RegisterModules();
+
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
Plugins = GetExports<IPlugin>();
}
@@ -449,7 +453,7 @@ namespace MediaBrowser.Common.Implementations
RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
- TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger);
+ TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger, FileSystemManager);
RegisterSingleInstance(JsonSerializer);
RegisterSingleInstance(XmlSerializer);
@@ -473,13 +477,12 @@ namespace MediaBrowser.Common.Implementations
InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager);
RegisterSingleInstance(InstallationManager);
- ZipClient = new ZipClient();
+ ZipClient = new ZipClient(FileSystemManager);
RegisterSingleInstance(ZipClient);
IsoManager = new IsoManager();
RegisterSingleInstance(IsoManager);
- RegisterModules();
return Task.FromResult (true);
}
@@ -522,6 +525,14 @@ namespace MediaBrowser.Common.Implementations
}
catch (ReflectionTypeLoadException ex)
{
+ if (ex.LoaderExceptions != null)
+ {
+ foreach (var loaderException in ex.LoaderExceptions)
+ {
+ Logger.Error("LoaderException: " + loaderException.Message);
+ }
+ }
+
// If it fails we can still get a list of the Types it was able to resolve
return ex.Types.Where(t => t != null);
}
@@ -581,7 +592,7 @@ namespace MediaBrowser.Common.Implementations
protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
where T : class
{
- Container.RegisterSingle(obj);
+ Container.RegisterSingleton(obj);
if (manageLifetime)
{
@@ -607,7 +618,7 @@ namespace MediaBrowser.Common.Implementations
protected void RegisterSingleInstance<T>(Func<T> func)
where T : class
{
- Container.RegisterSingle(func);
+ Container.RegisterSingleton(func);
}
void IDependencyContainer.Register(Type typeInterface, Type typeImplementation)
diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
index 1b9146644..7bbc1abd7 100644
--- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
@@ -9,6 +9,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Common.Implementations.Configuration
{
@@ -32,7 +34,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
/// Occurs when [configuration updating].
/// </summary>
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdating;
-
+
/// <summary>
/// Occurs when [named configuration updated].
/// </summary>
@@ -54,6 +56,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
/// </summary>
/// <value>The application paths.</value>
public IApplicationPaths CommonApplicationPaths { get; private set; }
+ public readonly IFileSystem FileSystem;
/// <summary>
/// The _configuration loaded
@@ -87,8 +90,8 @@ namespace MediaBrowser.Common.Implementations.Configuration
}
}
- private ConfigurationStore[] _configurationStores = {};
- private IConfigurationFactory[] _configurationFactories = {};
+ private ConfigurationStore[] _configurationStores = { };
+ private IConfigurationFactory[] _configurationFactories = { };
/// <summary>
/// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
@@ -96,10 +99,11 @@ namespace MediaBrowser.Common.Implementations.Configuration
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="xmlSerializer">The XML serializer.</param>
- protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer)
+ protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
{
CommonApplicationPaths = applicationPaths;
XmlSerializer = xmlSerializer;
+ FileSystem = fileSystem;
Logger = logManager.GetLogger(GetType().Name);
UpdateCachePath();
@@ -199,9 +203,19 @@ namespace MediaBrowser.Common.Implementations.Configuration
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
+
+ EnsureWriteAccess(newPath);
}
}
+ protected void EnsureWriteAccess(string path)
+ {
+ var file = Path.Combine(path, Guid.NewGuid().ToString());
+
+ FileSystem.WriteAllText(file, string.Empty);
+ FileSystem.DeleteFile(file);
+ }
+
private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
private string GetConfigurationFile(string key)
@@ -215,9 +229,15 @@ namespace MediaBrowser.Common.Implementations.Configuration
{
var file = GetConfigurationFile(key);
- var configurationType = _configurationStores
- .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
- .ConfigurationType;
+ var configurationInfo = _configurationStores
+ .FirstOrDefault(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
+
+ if (configurationInfo == null)
+ {
+ throw new ResourceNotFoundException("Configuration with key " + key + " not found.");
+ }
+
+ var configurationType = configurationInfo.ConfigurationType;
lock (_configurationSyncLock)
{
@@ -272,7 +292,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
NewConfiguration = configuration
}, Logger);
-
+
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
var path = GetConfigurationFile(key);
diff --git a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
index ff5b8bd59..276da58d4 100644
--- a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
+++ b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
@@ -2,6 +2,7 @@
using System;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Common.Implementations.Configuration
{
@@ -27,7 +28,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
// Use try/catch to avoid the extra file system lookup using File.Exists
try
{
- buffer = File.ReadAllBytes(path);
+ buffer = File.ReadAllBytes(path);
configuration = xmlSerializer.DeserializeFromBytes(type, buffer);
}
@@ -46,10 +47,10 @@ namespace MediaBrowser.Common.Implementations.Configuration
// If the file didn't exist before, or if something has changed, re-save
if (buffer == null || !buffer.SequenceEqual(newBytes))
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
// Save it after load in case we got new items
- File.WriteAllBytes(path, newBytes);
+ File.WriteAllBytes(path, newBytes);
}
return configuration;
diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
index 2a1c8877d..4cad3cd31 100644
--- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
+++ b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
@@ -3,13 +3,16 @@ using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Text;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Common.Implementations.Devices
{
public class DeviceId
{
private readonly IApplicationPaths _appPaths;
- private readonly ILogger _logger;
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
private readonly object _syncLock = new object();
@@ -24,7 +27,7 @@ namespace MediaBrowser.Common.Implementations.Devices
{
lock (_syncLock)
{
- var value = File.ReadAllText(CachePath, Encoding.UTF8);
+ var value = File.ReadAllText(CachePath, Encoding.UTF8);
Guid guid;
if (Guid.TryParse(value, out guid))
@@ -55,11 +58,11 @@ namespace MediaBrowser.Common.Implementations.Devices
{
var path = CachePath;
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_syncLock)
{
- File.WriteAllText(path, id, Encoding.UTF8);
+ _fileSystem.WriteAllText(path, id, Encoding.UTF8);
}
}
catch (Exception ex)
@@ -88,10 +91,15 @@ namespace MediaBrowser.Common.Implementations.Devices
private string _id;
- public DeviceId(IApplicationPaths appPaths, ILogger logger)
+ public DeviceId(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
{
+ if (fileSystem == null) {
+ throw new ArgumentNullException ("fileSystem");
+ }
+
_appPaths = appPaths;
_logger = logger;
+ _fileSystem = fileSystem;
}
public string Value
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index 89f405e8a..f4d4826eb 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -17,6 +17,7 @@ using System.Net.Cache;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.HttpClientManager
{
@@ -282,8 +283,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
var url = options.Url;
var urlHash = url.ToLower().GetMD5().ToString("N");
- var semaphore = GetLock(url);
-
+
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false);
@@ -292,6 +292,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
return response;
}
+ var semaphore = GetLock(url);
+
await semaphore.WaitAsync(options.CancellationToken).ConfigureAwait(false);
try
@@ -355,7 +357,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
private async Task CacheResponse(HttpResponseInfo response, string responseCachePath)
{
- Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(responseCachePath));
using (var responseStream = response.Content)
{
@@ -464,20 +466,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
catch (OperationCanceledException ex)
{
- var exception = GetCancellationException(options.Url, options.CancellationToken, ex);
-
- var httpException = exception as HttpException;
-
- if (httpException != null && httpException.IsTimedOut)
- {
- client.LastTimeout = DateTime.UtcNow;
- }
-
- throw exception;
+ throw GetCancellationException(options, client, options.CancellationToken, ex);
}
catch (Exception ex)
{
- throw GetException(ex, options);
+ throw GetException(ex, options, client);
}
finally
{
@@ -488,27 +481,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
}
- /// <summary>
- /// Gets the exception.
- /// </summary>
- /// <param name="ex">The ex.</param>
- /// <param name="options">The options.</param>
- /// <returns>HttpException.</returns>
- private HttpException GetException(WebException ex, HttpRequestOptions options)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
-
- var exception = new HttpException(ex.Message, ex);
-
- var response = ex.Response as HttpWebResponse;
- if (response != null)
- {
- exception.StatusCode = response.StatusCode;
- }
-
- return exception;
- }
-
private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable)
{
return new HttpResponseInfo(disposable)
@@ -599,7 +571,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
ValidateParams(options);
- Directory.CreateDirectory(_appPaths.TempDirectory);
+ _fileSystem.CreateDirectory(_appPaths.TempDirectory);
var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
@@ -624,6 +596,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger.Info("HttpClientManager.GetTempFileResponse url: {0}", options.Url);
}
+ var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
+
try
{
options.CancellationToken.ThrowIfCancellationRequested();
@@ -632,7 +606,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
var httpResponse = (HttpWebResponse)response;
- var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression);
EnsureSuccessStatusCode(client, httpResponse, options);
options.CancellationToken.ThrowIfCancellationRequested();
@@ -669,7 +642,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
catch (Exception ex)
{
DeleteTempFile(tempFile);
- throw GetException(ex, options);
+ throw GetException(ex, options, client);
}
finally
{
@@ -694,14 +667,37 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- private Exception GetException(Exception ex, HttpRequestOptions options)
+ private Exception GetException(Exception ex, HttpRequestOptions options, HttpClientInfo client)
{
+ if (ex is HttpException)
+ {
+ return ex;
+ }
+
var webException = ex as WebException
?? ex.InnerException as WebException;
if (webException != null)
{
- return GetException(webException, options);
+ if (options.LogErrors)
+ {
+ _logger.ErrorException("Error getting response from " + options.Url, ex);
+ }
+
+ var exception = new HttpException(ex.Message, ex);
+
+ var response = webException.Response as HttpWebResponse;
+ if (response != null)
+ {
+ exception.StatusCode = response.StatusCode;
+
+ if ((int)response.StatusCode == 429)
+ {
+ client.LastTimeout = DateTime.UtcNow;
+ }
+ }
+
+ return exception;
}
var operationCanceledException = ex as OperationCanceledException
@@ -709,10 +705,13 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
if (operationCanceledException != null)
{
- return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException);
+ return GetCancellationException(options, client, options.CancellationToken, operationCanceledException);
}
- _logger.ErrorException("Error getting response from " + options.Url, ex);
+ if (options.LogErrors)
+ {
+ _logger.ErrorException("Error getting response from " + options.Url, ex);
+ }
return ex;
}
@@ -784,18 +783,24 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <summary>
/// Throws the cancellation exception.
/// </summary>
- /// <param name="url">The URL.</param>
+ /// <param name="options">The options.</param>
+ /// <param name="client">The client.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="exception">The exception.</param>
/// <returns>Exception.</returns>
- private Exception GetCancellationException(string url, CancellationToken cancellationToken, OperationCanceledException exception)
+ private Exception GetCancellationException(HttpRequestOptions options, HttpClientInfo client, CancellationToken cancellationToken, OperationCanceledException exception)
{
// If the HttpClient's timeout is reached, it will cancel the Task internally
if (!cancellationToken.IsCancellationRequested)
{
- var msg = string.Format("Connection to {0} timed out", url);
+ var msg = string.Format("Connection to {0} timed out", options.Url);
+
+ if (options.LogErrors)
+ {
+ _logger.Error(msg);
+ }
- _logger.Error(msg);
+ client.LastTimeout = DateTime.UtcNow;
// Throw an HttpException so that the caller doesn't think it was cancelled by user code
return new HttpException(msg, exception)
@@ -815,12 +820,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
if (!isSuccessful)
{
- if ((int) statusCode == 429)
- {
- client.LastTimeout = DateTime.UtcNow;
- }
-
- if (statusCode == HttpStatusCode.RequestEntityTooLarge)
if (options.LogErrorResponseBody)
{
try
@@ -869,25 +868,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true);
- asyncTask.ContinueWith(task =>
- {
- taskCompletion.TrySetResult(task.Result);
-
- }, TaskContinuationOptions.NotOnFaulted);
+ var callback = new TaskCallback { taskCompletion = taskCompletion };
+ asyncTask.ContinueWith(callback.OnSuccess, TaskContinuationOptions.NotOnFaulted);
// Handle errors
- asyncTask.ContinueWith(task =>
- {
- if (task.Exception != null)
- {
- taskCompletion.TrySetException(task.Exception);
- }
- else
- {
- taskCompletion.TrySetException(new List<Exception>());
- }
-
- }, TaskContinuationOptions.OnlyOnFaulted);
+ asyncTask.ContinueWith(callback.OnError, TaskContinuationOptions.OnlyOnFaulted);
return taskCompletion.Task;
}
@@ -903,5 +888,27 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
}
}
+
+ private class TaskCallback
+ {
+ public TaskCompletionSource<WebResponse> taskCompletion;
+
+ public void OnSuccess(Task<WebResponse> task)
+ {
+ taskCompletion.TrySetResult(task.Result);
+ }
+
+ public void OnError(Task<WebResponse> task)
+ {
+ if (task.Exception != null)
+ {
+ taskCompletion.TrySetException(task.Exception);
+ }
+ else
+ {
+ taskCompletion.TrySetException(new List<Exception>());
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
deleted file mode 100644
index e9ef84663..000000000
--- a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
+++ /dev/null
@@ -1,433 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Text;
-
-namespace MediaBrowser.Common.Implementations.IO
-{
- /// <summary>
- /// Class CommonFileSystem
- /// </summary>
- public class CommonFileSystem : IFileSystem
- {
- protected ILogger Logger;
-
- private readonly bool _supportsAsyncFileStreams;
- private char[] _invalidFileNameChars;
-
- public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool usePresetInvalidFileNameChars)
- {
- Logger = logger;
- _supportsAsyncFileStreams = supportsAsyncFileStreams;
-
- SetInvalidFileNameChars(usePresetInvalidFileNameChars);
- }
-
- private void SetInvalidFileNameChars(bool usePresetInvalidFileNameChars)
- {
- // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
-
- if (usePresetInvalidFileNameChars)
- {
- _invalidFileNameChars = new char[41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
- '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
- '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
- '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' };
- }
- else
- {
- _invalidFileNameChars = Path.GetInvalidFileNameChars();
- }
- }
-
- /// <summary>
- /// Determines whether the specified filename is shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public virtual bool IsShortcut(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- var extension = Path.GetExtension(filename);
-
- return string.Equals(extension, ".mblink", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Resolves the shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public virtual string ResolveShortcut(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- if (string.Equals(Path.GetExtension(filename), ".mblink", StringComparison.OrdinalIgnoreCase))
- {
- var path = File.ReadAllText(filename);
-
- return NormalizePath(path);
- }
-
- return null;
- }
-
- /// <summary>
- /// Creates the shortcut.
- /// </summary>
- /// <param name="shortcutPath">The shortcut path.</param>
- /// <param name="target">The target.</param>
- /// <exception cref="System.ArgumentNullException">
- /// shortcutPath
- /// or
- /// target
- /// </exception>
- public void CreateShortcut(string shortcutPath, string target)
- {
- if (string.IsNullOrEmpty(shortcutPath))
- {
- throw new ArgumentNullException("shortcutPath");
- }
-
- if (string.IsNullOrEmpty(target))
- {
- throw new ArgumentNullException("target");
- }
-
- File.WriteAllText(shortcutPath, target);
- }
-
- /// <summary>
- /// Gets the file system info.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>FileSystemInfo.</returns>
- public FileSystemInfo GetFileSystemInfo(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- // Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists
- if (Path.HasExtension(path))
- {
- var fileInfo = new FileInfo(path);
-
- if (fileInfo.Exists)
- {
- return fileInfo;
- }
-
- return new DirectoryInfo(path);
- }
- else
- {
- var fileInfo = new DirectoryInfo(path);
-
- if (fileInfo.Exists)
- {
- return fileInfo;
- }
-
- return new FileInfo(path);
- }
- }
-
- /// <summary>
- /// The space char
- /// </summary>
- private const char SpaceChar = ' ';
-
- /// <summary>
- /// Takes a filename and removes invalid characters
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">filename</exception>
- public string GetValidFilename(string filename)
- {
- if (string.IsNullOrEmpty(filename))
- {
- throw new ArgumentNullException("filename");
- }
-
- var builder = new StringBuilder(filename);
-
- foreach (var c in _invalidFileNameChars)
- {
- builder = builder.Replace(c, SpaceChar);
- }
-
- return builder.ToString();
- }
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetCreationTimeUtc(FileSystemInfo info)
- {
- // This could throw an error on some file systems that have dates out of range
- try
- {
- return info.CreationTimeUtc;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining CreationTimeUtc for {0}", ex, info.FullName);
- return DateTime.MinValue;
- }
- }
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
- {
- // This could throw an error on some file systems that have dates out of range
- try
- {
- return info.LastWriteTimeUtc;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
- return DateTime.MinValue;
- }
- }
-
- /// <summary>
- /// Gets the last write time UTC.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>DateTime.</returns>
- public DateTime GetLastWriteTimeUtc(string path)
- {
- return GetLastWriteTimeUtc(GetFileSystemInfo(path));
- }
-
- /// <summary>
- /// Gets the file stream.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="mode">The mode.</param>
- /// <param name="access">The access.</param>
- /// <param name="share">The share.</param>
- /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
- /// <returns>FileStream.</returns>
- public FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false)
- {
- if (_supportsAsyncFileStreams && isAsync)
- {
- return new FileStream(path, mode, access, share, StreamDefaults.DefaultFileStreamBufferSize, true);
- }
-
- return new FileStream(path, mode, access, share, StreamDefaults.DefaultFileStreamBufferSize);
- }
-
- /// <summary>
- /// Swaps the files.
- /// </summary>
- /// <param name="file1">The file1.</param>
- /// <param name="file2">The file2.</param>
- public void SwapFiles(string file1, string file2)
- {
- if (string.IsNullOrEmpty(file1))
- {
- throw new ArgumentNullException("file1");
- }
-
- if (string.IsNullOrEmpty(file2))
- {
- throw new ArgumentNullException("file2");
- }
-
- var temp1 = Path.GetTempFileName();
- var temp2 = Path.GetTempFileName();
-
- // Copying over will fail against hidden files
- RemoveHiddenAttribute(file1);
- RemoveHiddenAttribute(file2);
-
- File.Copy(file1, temp1, true);
- File.Copy(file2, temp2, true);
-
- File.Copy(temp1, file2, true);
- File.Copy(temp2, file1, true);
-
- DeleteFile(temp1);
- DeleteFile(temp2);
- }
-
- /// <summary>
- /// Removes the hidden attribute.
- /// </summary>
- /// <param name="path">The path.</param>
- private void RemoveHiddenAttribute(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var currentFile = new FileInfo(path);
-
- // This will fail if the file is hidden
- if (currentFile.Exists)
- {
- if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- {
- currentFile.Attributes &= ~FileAttributes.Hidden;
- }
- }
- }
-
- public bool ContainsSubPath(string parentPath, string path)
- {
- if (string.IsNullOrEmpty(parentPath))
- {
- throw new ArgumentNullException("parentPath");
- }
-
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- return path.IndexOf(parentPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- public bool IsRootPath(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var parent = Path.GetDirectoryName(path);
-
- if (!string.IsNullOrEmpty(parent))
- {
- return false;
- }
-
- return true;
- }
-
- public string NormalizePath(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
- {
- return path;
- }
-
- return path.TrimEnd(Path.DirectorySeparatorChar);
- }
-
- public string SubstitutePath(string path, string from, string to)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
- if (string.IsNullOrWhiteSpace(from))
- {
- throw new ArgumentNullException("from");
- }
- if (string.IsNullOrWhiteSpace(to))
- {
- throw new ArgumentNullException("to");
- }
-
- var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
-
- if (!string.Equals(newPath, path))
- {
- if (to.IndexOf('/') != -1)
- {
- newPath = newPath.Replace('\\', '/');
- }
- else
- {
- newPath = newPath.Replace('/', '\\');
- }
- }
-
- return newPath;
- }
-
- public string GetFileNameWithoutExtension(FileSystemInfo info)
- {
- if (info is DirectoryInfo)
- {
- return info.Name;
- }
-
- return Path.GetFileNameWithoutExtension(info.FullName);
- }
-
- public string GetFileNameWithoutExtension(string path)
- {
- return Path.GetFileNameWithoutExtension(path);
- }
-
- public bool IsPathFile(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\
-
- if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
- !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- return true;
-
- //return Path.IsPathRooted(path);
- }
-
- public void DeleteFile(string path, bool sendToRecycleBin)
- {
- File.Delete(path);
- }
-
- public void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin)
- {
- Directory.Delete(path, recursive);
- }
-
- public void DeleteFile(string path)
- {
- DeleteFile(path, false);
- }
-
- public void DeleteDirectory(string path, bool recursive)
- {
- DeleteDirectory(path, recursive, false);
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
index 698792802..391e7c212 100644
--- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
+++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
@@ -170,7 +170,7 @@ namespace MediaBrowser.Common.Implementations.Logging
/// </summary>
/// <param name="name">The name.</param>
/// <returns>ILogger.</returns>
- public ILogger GetLogger(string name)
+ public Model.Logging.ILogger GetLogger(string name)
{
return new NLogger(name, this);
}
@@ -208,7 +208,7 @@ namespace MediaBrowser.Common.Implementations.Logging
{
LogFilePath = Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Round(DateTime.Now.Ticks / 10000000) + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
+ Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
AddFileTarget(LogFilePath, level);
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index e603ea373..d857e58b6 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -14,7 +14,6 @@
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -48,18 +47,24 @@
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
- <Reference Include="NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\NLog.3.2.1\lib\net45\NLog.dll</HintPath>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\NLog.4.1.1\lib\net45\NLog.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
</Reference>
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <Reference Include="SimpleInjector, Version=2.8.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SimpleInjector.3.0.5\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -82,7 +87,6 @@
<Compile Include="Devices\DeviceId.cs" />
<Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" />
- <Compile Include="IO\CommonFileSystem.cs" />
<Compile Include="IO\IsoManager.cs" />
<Compile Include="Logging\LogHelper.cs" />
<Compile Include="Logging\NLogger.cs" />
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index cbd1c1ac5..95f29915d 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
@@ -51,6 +52,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// </summary>
/// <value>The task manager.</value>
private ITaskManager TaskManager { get; set; }
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class.
@@ -71,7 +73,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// or
/// logger
/// </exception>
- public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger)
+ public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger, IFileSystem fileSystem)
{
if (scheduledTask == null)
{
@@ -99,6 +101,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
TaskManager = taskManager;
JsonSerializer = jsonSerializer;
Logger = logger;
+ _fileSystem = fileSystem;
ReloadTriggerEvents(true);
}
@@ -154,7 +157,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
_lastExecutionResult = value;
var path = GetHistoryFilePath();
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_lastExecutionResultSyncLock)
{
@@ -300,6 +303,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
}
}
+ public void ReloadTriggerEvents()
+ {
+ ReloadTriggerEvents(false);
+ }
+
/// <summary>
/// Reloads the trigger events.
/// </summary>
@@ -552,7 +560,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
var path = GetConfigurationFilePath();
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
JsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), path);
}
@@ -622,7 +630,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
try
{
- Logger.Debug(Name + ": Cancelling");
+ Logger.Info(Name + ": Cancelling");
token.Cancel();
}
catch (Exception ex)
@@ -635,16 +643,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
try
{
- Logger.Debug(Name + ": Waiting on Task");
+ Logger.Info(Name + ": Waiting on Task");
var exited = Task.WaitAll(new[] { task }, 2000);
if (exited)
{
- Logger.Debug(Name + ": Task exited");
+ Logger.Info(Name + ": Task exited");
}
else
{
- Logger.Debug(Name + ": Timed out waiting for task to stop");
+ Logger.Info(Name + ": Timed out waiting for task to stop");
}
}
catch (Exception ex)
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
index de7987bd2..845c984fb 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
@@ -10,6 +10,9 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
+using Microsoft.Win32;
namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
@@ -50,6 +53,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// </summary>
/// <value>The logger.</value>
private ILogger Logger { get; set; }
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="TaskManager" /> class.
@@ -58,13 +62,36 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <exception cref="System.ArgumentException">kernel</exception>
- public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger)
+ public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger, IFileSystem fileSystem)
{
ApplicationPaths = applicationPaths;
JsonSerializer = jsonSerializer;
Logger = logger;
+ _fileSystem = fileSystem;
ScheduledTasks = new IScheduledTaskWorker[] { };
+
+ BindToSystemEvent();
+ }
+
+ private void BindToSystemEvent()
+ {
+ try
+ {
+ SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+ }
+ catch
+ {
+
+ }
+ }
+
+ void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ foreach (var task in ScheduledTasks)
+ {
+ task.ReloadTriggerEvents();
+ }
}
/// <summary>
@@ -106,9 +133,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
public void QueueScheduledTask<T>(TaskExecutionOptions options)
where T : IScheduledTask
{
- var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
+ var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T));
- QueueScheduledTask(scheduledTask, options);
+ if (scheduledTask == null)
+ {
+ Logger.Error("Unable to find scheduled task of type {0} in QueueScheduledTask.", typeof(T).Name);
+ }
+ else
+ {
+ QueueScheduledTask(scheduledTask, options);
+ }
}
public void QueueScheduledTask<T>()
@@ -116,7 +150,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
{
QueueScheduledTask<T>(new TaskExecutionOptions());
}
-
+
/// <summary>
/// Queues the scheduled task.
/// </summary>
@@ -124,9 +158,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
/// <param name="options">The task options.</param>
public void QueueScheduledTask(IScheduledTask task, TaskExecutionOptions options)
{
- var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == task.GetType());
+ var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == task.GetType());
- QueueScheduledTask(scheduledTask, options);
+ if (scheduledTask == null)
+ {
+ Logger.Error("Unable to find scheduled task of type {0} in QueueScheduledTask.", task.GetType().Name);
+ }
+ else
+ {
+ QueueScheduledTask(scheduledTask, options);
+ }
}
/// <summary>
@@ -161,7 +202,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
var myTasks = ScheduledTasks.ToList();
var list = tasks.ToList();
- myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger)));
+ myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem)));
ScheduledTasks = myTasks.ToArray();
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index d9c178d8b..0e50f9315 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
{
@@ -95,7 +96,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
/// <param name="progress">The progress.</param>
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
{
- var filesToDelete = new DirectoryInfo(directory).EnumerateFiles("*", SearchOption.AllDirectories)
+ var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
.ToList();
@@ -120,14 +121,14 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
progress.Report(100);
}
- private static void DeleteEmptyFolders(string parent)
+ private void DeleteEmptyFolders(string parent)
{
- foreach (var directory in Directory.GetDirectories(parent))
+ foreach (var directory in _fileSystem.GetDirectoryPaths(parent))
{
DeleteEmptyFolders(directory);
- if (!Directory.EnumerateFileSystemEntries(directory).Any())
+ if (!_fileSystem.GetFileSystemEntryPaths(directory).Any())
{
- Directory.Delete(directory, false);
+ _fileSystem.DeleteDirectory(directory, false);
}
}
}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index b2759c52a..8507d3184 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
{
@@ -58,7 +59,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
// Delete log files more than n days old
var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays));
- var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
+ var filesToDelete = _fileSystem.GetFiles(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
.ToList();
diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
index 63381efcd..79e558794 100644
--- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
+++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.Common.Implementations.Security
{
try
{
- contents = File.ReadAllLines(licenseFile);
+ contents = File.ReadAllLines(licenseFile);
}
catch (DirectoryNotFoundException)
{
@@ -107,7 +107,7 @@ namespace MediaBrowser.Common.Implementations.Security
}
catch (FileNotFoundException)
{
- (File.Create(licenseFile)).Close();
+ (File.Create(licenseFile)).Close();
}
}
if (contents != null && contents.Length > 0)
@@ -150,8 +150,8 @@ namespace MediaBrowser.Common.Implementations.Security
}
var licenseFile = Filename;
- Directory.CreateDirectory(Path.GetDirectoryName(licenseFile));
- lock (_fileLock) File.WriteAllLines(licenseFile, lines);
+ Directory.CreateDirectory(Path.GetDirectoryName(licenseFile));
+ lock (_fileLock) File.WriteAllLines(licenseFile, lines);
}
}
}
diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
index c2725e9bf..c17a637fe 100644
--- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
+++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System.IO;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Model.Entities;
@@ -18,6 +19,7 @@ namespace MediaBrowser.Common.Implementations.Security
public class PluginSecurityManager : ISecurityManager
{
private const string MBValidateUrl = MbAdmin.HttpsUrl + "service/registration/validate";
+ private const string AppstoreRegUrl = /*MbAdmin.HttpsUrl*/ "http://mb3admin.com/admin/" + "service/appstore/register";
/// <summary>
/// The _is MB supporter
@@ -185,6 +187,70 @@ namespace MediaBrowser.Common.Implementations.Security
}
}
+ /// <summary>
+ /// Register an app store sale with our back-end. It will validate the transaction with the store
+ /// and then register the proper feature and then fill in the supporter key on success.
+ /// </summary>
+ /// <param name="parameters">Json parameters to send to admin server</param>
+ public async Task RegisterAppStoreSale(string parameters)
+ {
+ var options = new HttpRequestOptions()
+ {
+ Url = AppstoreRegUrl,
+ CancellationToken = CancellationToken.None
+ };
+ options.RequestHeaders.Add("X-Emby-Token", _appHost.SystemId);
+ options.RequestContent = parameters;
+ options.RequestContentType = "application/json";
+
+ try
+ {
+ using (var response = await _httpClient.Post(options).ConfigureAwait(false))
+ {
+ var reg = _jsonSerializer.DeserializeFromStream<RegRecord>(response.Content);
+
+ if (reg == null)
+ {
+ var msg = "Result from appstore registration was null.";
+ _logger.Error(msg);
+ throw new ApplicationException(msg);
+ }
+ if (!String.IsNullOrEmpty(reg.key))
+ {
+ SupporterKey = reg.key;
+ }
+ }
+
+ }
+ catch (ApplicationException)
+ {
+ SaveAppStoreInfo(parameters);
+ throw;
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT");
+ SaveAppStoreInfo(parameters);
+ //TODO - could create a re-try routine on start-up if this file is there. For now we can handle manually.
+ throw new ApplicationException("Error registering store sale");
+ }
+
+ }
+
+ private void SaveAppStoreInfo(string info)
+ {
+ // Save all transaction information to a file
+
+ try
+ {
+ File.WriteAllText(Path.Combine(_appPaths.ProgramDataPath, "apptrans-error.txt"), info);
+ }
+ catch (IOException)
+ {
+
+ }
+ }
+
private async Task<MBRegistrationRecord> GetRegistrationStatusInternal(string feature,
string mb2Equivalent = null,
string version = null)
diff --git a/MediaBrowser.Common.Implementations/Security/RegRecord.cs b/MediaBrowser.Common.Implementations/Security/RegRecord.cs
index f4e4337bf..ece70b772 100644
--- a/MediaBrowser.Common.Implementations/Security/RegRecord.cs
+++ b/MediaBrowser.Common.Implementations/Security/RegRecord.cs
@@ -7,5 +7,6 @@ namespace MediaBrowser.Common.Implementations.Security
public string featId { get; set; }
public bool registered { get; set; }
public DateTime expDate { get; set; }
+ public string key { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
index f194b334a..269294b36 100644
--- a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
+++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
@@ -1,6 +1,8 @@
-using MediaBrowser.Model.Serialization;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Model.Serialization;
using System;
using System.IO;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.Serialization
{
@@ -9,8 +11,11 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// </summary>
public class JsonSerializer : IJsonSerializer
{
- public JsonSerializer()
+ private readonly IFileSystem _fileSystem;
+
+ public JsonSerializer(IFileSystem fileSystem)
{
+ _fileSystem = fileSystem;
Configure();
}
@@ -53,7 +58,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
throw new ArgumentNullException("file");
}
- using (Stream stream = File.Open(file, FileMode.Create))
+ using (Stream stream = _fileSystem.GetFileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read))
{
SerializeToStream(obj, stream);
}
diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
index 04030522f..449c23b2d 100644
--- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
+++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
@@ -3,6 +3,8 @@ using System;
using System.Collections.Concurrent;
using System.IO;
using System.Xml;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Common.Implementations.Serialization
{
@@ -11,6 +13,13 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// </summary>
public class XmlSerializer : IXmlSerializer
{
+ private IFileSystem _fileSystem;
+
+ public XmlSerializer(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
// Need to cache these
// http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
private readonly ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer> _serializers =
@@ -83,7 +92,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// <returns>System.Object.</returns>
public object DeserializeFromFile(Type type, string file)
{
- using (var stream = File.OpenRead(file))
+ using (var stream = _fileSystem.OpenRead(file))
{
return DeserializeFromStream(type, stream);
}
diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
index 5f205d69e..dc642a0a8 100644
--- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
+++ b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
@@ -19,6 +19,7 @@ using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Common.Implementations.Updates
{
@@ -553,7 +554,7 @@ namespace MediaBrowser.Common.Implementations.Updates
if (packageChecksum != Guid.Empty) // support for legacy uploads for now
{
using (var crypto = new MD5CryptoServiceProvider())
- using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000))
+ using (var stream = new BufferedStream(_fileSystem.OpenRead(tempFile), 100000))
{
var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty));
if (check != packageChecksum)
@@ -568,12 +569,12 @@ namespace MediaBrowser.Common.Implementations.Updates
// Success - move it to the real target
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(target));
- File.Copy(tempFile, target, true);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(target));
+ _fileSystem.CopyFile(tempFile, target, true);
//If it is an archive - write out a version file so we know what it is
if (isArchive)
{
- File.WriteAllText(target + ".ver", package.versionStr);
+ File.WriteAllText(target + ".ver", package.versionStr);
}
}
catch (IOException e)
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index e57c874f2..a0711a9c7 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="NLog" version="3.2.1" targetFramework="net45" />
- <package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
+ <package id="NLog" version="4.1.0" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
+ <package id="SimpleInjector" version="3.0.5" targetFramework="net45" />
</packages>
diff --git a/MediaBrowser.Common/IO/IFileSystem.cs b/MediaBrowser.Common/IO/IFileSystem.cs
deleted file mode 100644
index 5ce84f436..000000000
--- a/MediaBrowser.Common/IO/IFileSystem.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using System;
-using System.IO;
-
-namespace MediaBrowser.Common.IO
-{
- /// <summary>
- /// Interface IFileSystem
- /// </summary>
- public interface IFileSystem
- {
- /// <summary>
- /// Determines whether the specified filename is shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns><c>true</c> if the specified filename is shortcut; otherwise, <c>false</c>.</returns>
- bool IsShortcut(string filename);
-
- /// <summary>
- /// Resolves the shortcut.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- string ResolveShortcut(string filename);
-
- /// <summary>
- /// Creates the shortcut.
- /// </summary>
- /// <param name="shortcutPath">The shortcut path.</param>
- /// <param name="target">The target.</param>
- void CreateShortcut(string shortcutPath, string target);
-
- /// <summary>
- /// Gets the file system info.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>FileSystemInfo.</returns>
- FileSystemInfo GetFileSystemInfo(string path);
-
- /// <summary>
- /// Gets the valid filename.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.String.</returns>
- string GetValidFilename(string filename);
-
- /// <summary>
- /// Gets the creation time UTC.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>DateTime.</returns>
- DateTime GetCreationTimeUtc(FileSystemInfo info);
-
- /// <summary>
- /// Gets the last write time UTC.
- /// </summary>
- /// <param name="info">The information.</param>
- /// <returns>DateTime.</returns>
- DateTime GetLastWriteTimeUtc(FileSystemInfo info);
-
- /// <summary>
- /// Gets the last write time UTC.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>DateTime.</returns>
- DateTime GetLastWriteTimeUtc(string path);
-
- /// <summary>
- /// Gets the file stream.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="mode">The mode.</param>
- /// <param name="access">The access.</param>
- /// <param name="share">The share.</param>
- /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
- /// <returns>FileStream.</returns>
- FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
-
- /// <summary>
- /// Swaps the files.
- /// </summary>
- /// <param name="file1">The file1.</param>
- /// <param name="file2">The file2.</param>
- void SwapFiles(string file1, string file2);
-
- /// <summary>
- /// Determines whether [contains sub path] [the specified parent path].
- /// </summary>
- /// <param name="parentPath">The parent path.</param>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [contains sub path] [the specified parent path]; otherwise, <c>false</c>.</returns>
- bool ContainsSubPath(string parentPath, string path);
-
- /// <summary>
- /// Determines whether [is root path] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is root path] [the specified path]; otherwise, <c>false</c>.</returns>
- bool IsRootPath(string path);
-
- /// <summary>
- /// Normalizes the path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- string NormalizePath(string path);
-
- /// <summary>
- /// Substitutes the path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="from">From.</param>
- /// <param name="to">To.</param>
- /// <returns>System.String.</returns>
- string SubstitutePath(string path, string from, string to);
-
- /// <summary>
- /// Gets the file name without extension.
- /// </summary>
- /// <param name="info">The information.</param>
- /// <returns>System.String.</returns>
- string GetFileNameWithoutExtension(FileSystemInfo info);
-
- /// <summary>
- /// Gets the file name without extension.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- string GetFileNameWithoutExtension(string path);
-
- /// <summary>
- /// Determines whether [is path file] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is path file] [the specified path]; otherwise, <c>false</c>.</returns>
- bool IsPathFile(string path);
-
- /// <summary>
- /// Deletes the file.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
- void DeleteFile(string path, bool sendToRecycleBin);
-
- /// <summary>
- /// Deletes the directory.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="recursive">if set to <c>true</c> [recursive].</param>
- /// <param name="sendToRecycleBin">if set to <c>true</c> [send to recycle bin].</param>
- void DeleteDirectory(string path, bool recursive, bool sendToRecycleBin);
-
- /// <summary>
- /// Deletes the file.
- /// </summary>
- /// <param name="path">The path.</param>
- void DeleteFile(string path);
-
- /// <summary>
- /// Deletes the directory.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="recursive">if set to <c>true</c> [recursive].</param>
- void DeleteDirectory(string path, bool recursive);
- }
-}
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index ad0c0cecd..b2f62dd21 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -60,7 +60,6 @@
<Compile Include="Extensions\BaseExtensions.cs" />
<Compile Include="Extensions\ResourceNotFoundException.cs" />
<Compile Include="IDependencyContainer.cs" />
- <Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\ProgressStream.cs" />
<Compile Include="IO\StreamDefaults.cs" />
<Compile Include="Configuration\IApplicationPaths.cs" />
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index 81f1d70d3..8c1f63e53 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -87,6 +87,7 @@ namespace MediaBrowser.Common.Net
public bool BufferContent { get; set; }
public bool LogRequest { get; set; }
+ public bool LogErrors { get; set; }
public bool LogErrorResponseBody { get; set; }
public bool EnableKeepAlive { get; set; }
@@ -116,6 +117,7 @@ namespace MediaBrowser.Common.Net
RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
LogRequest = true;
+ LogErrors = true;
CacheMode = CacheMode.None;
TimeoutMs = 20000;
diff --git a/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs b/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
index f50bd9e76..0b9a5e276 100644
--- a/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
+++ b/MediaBrowser.Common/ScheduledTasks/IScheduledTaskWorker.cs
@@ -69,5 +69,10 @@ namespace MediaBrowser.Common.ScheduledTasks
/// </summary>
/// <value>The unique id.</value>
string Id { get; }
+
+ /// <summary>
+ /// Reloads the trigger events.
+ /// </summary>
+ void ReloadTriggerEvents();
}
} \ No newline at end of file
diff --git a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
index 864131eef..a12fea14c 100644
--- a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
@@ -51,8 +51,8 @@ namespace MediaBrowser.Common.ScheduledTasks
DisposeTimer();
var triggerDate = lastResult != null ?
- lastResult.EndTimeUtc.Add(Interval) :
- DateTime.UtcNow.Add(FirstRunDelay);
+ lastResult.EndTimeUtc.Add(Interval) :
+ DateTime.UtcNow.Add(FirstRunDelay);
if (DateTime.UtcNow > triggerDate)
{
@@ -62,7 +62,7 @@ namespace MediaBrowser.Common.ScheduledTasks
}
else
{
- triggerDate = DateTime.UtcNow.Add(Interval);
+ triggerDate = DateTime.UtcNow.AddMinutes(1);
}
}
diff --git a/MediaBrowser.Common/Security/ISecurityManager.cs b/MediaBrowser.Common/Security/ISecurityManager.cs
index 935454353..729de911b 100644
--- a/MediaBrowser.Common/Security/ISecurityManager.cs
+++ b/MediaBrowser.Common/Security/ISecurityManager.cs
@@ -1,3 +1,4 @@
+using System;
using MediaBrowser.Model.Entities;
using System.Threading.Tasks;
@@ -45,5 +46,11 @@ namespace MediaBrowser.Common.Security
/// </summary>
/// <returns>Task&lt;SupporterInfo&gt;.</returns>
Task<SupporterInfo> GetSupporterInfo();
+
+ /// <summary>
+ /// Register and app store sale with our back-end
+ /// </summary>
+ /// <param name="parameters">Json parameters to pass to admin server</param>
+ Task RegisterAppStoreSale(string parameters);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index f0328a1d8..839b7d68f 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -10,8 +10,6 @@ namespace MediaBrowser.Controller.Channels
{
public class Channel : Folder
{
- public string OriginalChannelName { get; set; }
-
public override bool IsVisible(User user)
{
if (user.Policy.BlockedChannels != null)
diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
index aa4b6731c..653cec901 100644
--- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
@@ -7,24 +7,15 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.Serialization;
using System.Threading;
namespace MediaBrowser.Controller.Channels
{
public class ChannelAudioItem : Audio, IChannelMediaItem
{
- public string ExternalId { get; set; }
-
- public string DataVersion { get; set; }
-
- public ChannelItemType ChannelItemType { get; set; }
-
- public bool IsInfiniteStream { get; set; }
-
public ChannelMediaContentType ContentType { get; set; }
- public string OriginalImageUrl { get; set; }
-
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
protected override bool GetBlockUnratedValue(UserPolicy config)
@@ -37,6 +28,7 @@ namespace MediaBrowser.Controller.Channels
return ExternalId;
}
+ [IgnoreDataMember]
public override bool SupportsLocalMetadata
{
get
@@ -55,6 +47,7 @@ namespace MediaBrowser.Controller.Channels
ChannelMediaSources = new List<ChannelMediaInfo>();
}
+ [IgnoreDataMember]
public override LocationType LocationType
{
get
diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
index 7e9da52a9..9010470f8 100644
--- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
@@ -3,28 +3,24 @@ using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Users;
using System;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Channels
{
public class ChannelFolderItem : Folder, IChannelItem
{
- public string ExternalId { get; set; }
-
- public string DataVersion { get; set; }
-
- public ChannelItemType ChannelItemType { get; set; }
public ChannelFolderType ChannelFolderType { get; set; }
- public string OriginalImageUrl { get; set; }
-
protected override bool GetBlockUnratedValue(UserPolicy config)
{
// Don't block.
return false;
}
+ [IgnoreDataMember]
public override bool SupportsLocalMetadata
{
get
diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
index ca5e343f8..fb545e57a 100644
--- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
@@ -8,24 +8,15 @@ using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Runtime.Serialization;
using System.Threading;
namespace MediaBrowser.Controller.Channels
{
public class ChannelVideoItem : Video, IChannelMediaItem, IHasLookupInfo<ChannelItemLookupInfo>
{
- public string ExternalId { get; set; }
-
- public string DataVersion { get; set; }
-
- public ChannelItemType ChannelItemType { get; set; }
-
- public bool IsInfiniteStream { get; set; }
-
public ChannelMediaContentType ContentType { get; set; }
- public string OriginalImageUrl { get; set; }
-
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
protected override string CreateUserDataKey()
@@ -56,6 +47,7 @@ namespace MediaBrowser.Controller.Channels
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
}
+ [IgnoreDataMember]
public override bool SupportsLocalMetadata
{
get
@@ -74,6 +66,7 @@ namespace MediaBrowser.Controller.Channels
ChannelMediaSources = new List<ChannelMediaInfo>();
}
+ [IgnoreDataMember]
public override LocationType LocationType
{
get
@@ -115,7 +108,11 @@ namespace MediaBrowser.Controller.Channels
var info = GetItemLookupInfo<ChannelItemLookupInfo>();
info.ContentType = ContentType;
- info.ExtraType = ExtraType;
+
+ if (ExtraType.HasValue)
+ {
+ info.ExtraType = ExtraType.Value;
+ }
return info;
}
diff --git a/MediaBrowser.Controller/Channels/IChannelFactory.cs b/MediaBrowser.Controller/Channels/IChannelFactory.cs
deleted file mode 100644
index c7ed92586..000000000
--- a/MediaBrowser.Controller/Channels/IChannelFactory.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Channels
-{
- public interface IChannelFactory
- {
- IEnumerable<IChannel> GetChannels();
- }
-
- public interface IFactoryChannel
- {
-
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Channels/IChannelItem.cs b/MediaBrowser.Controller/Channels/IChannelItem.cs
index 7eb865b5b..9b5f0359b 100644
--- a/MediaBrowser.Controller/Channels/IChannelItem.cs
+++ b/MediaBrowser.Controller/Channels/IChannelItem.cs
@@ -7,11 +7,5 @@ namespace MediaBrowser.Controller.Channels
string ChannelId { get; set; }
string ExternalId { get; set; }
-
- ChannelItemType ChannelItemType { get; set; }
-
- string OriginalImageUrl { get; set; }
-
- string DataVersion { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs
index 8d3e0f596..fec550df8 100644
--- a/MediaBrowser.Controller/Channels/IChannelManager.cs
+++ b/MediaBrowser.Controller/Channels/IChannelManager.cs
@@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Channels
/// </summary>
/// <param name="channels">The channels.</param>
/// <param name="factories">The factories.</param>
- void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories);
+ void AddParts(IEnumerable<IChannel> channels);
/// <summary>
/// Gets the channel download path.
diff --git a/MediaBrowser.Controller/Channels/IChannelMediaItem.cs b/MediaBrowser.Controller/Channels/IChannelMediaItem.cs
index 50df07e72..60a29da90 100644
--- a/MediaBrowser.Controller/Channels/IChannelMediaItem.cs
+++ b/MediaBrowser.Controller/Channels/IChannelMediaItem.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Channels
ChannelMediaContentType ContentType { get; set; }
- ExtraType ExtraType { get; set; }
+ ExtraType? ExtraType { get; set; }
List<ChannelMediaInfo> ChannelMediaSources { get; set; }
}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index aeb817392..e1e98857f 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -28,17 +28,17 @@ namespace MediaBrowser.Controller.Drawing
/// <summary>
/// Gets the size of the image.
/// </summary>
- /// <param name="path">The path.</param>
+ /// <param name="info">The information.</param>
/// <returns>ImageSize.</returns>
- ImageSize GetImageSize(string path);
+ ImageSize GetImageSize(ItemImageInfo info);
/// <summary>
/// Gets the size of the image.
/// </summary>
- /// <param name="info">The information.</param>
+ /// <param name="path">The path.</param>
/// <returns>ImageSize.</returns>
- ImageSize GetImageSize(ItemImageInfo info);
-
+ ImageSize GetImageSize(string path);
+
/// <summary>
/// Adds the parts.
/// </summary>
@@ -105,5 +105,11 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <param name="options">The options.</param>
Task CreateImageCollage(ImageCollageOptions options);
+
+ /// <summary>
+ /// Gets a value indicating whether [supports image collage creation].
+ /// </summary>
+ /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
+ bool SupportsImageCollageCreation { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index 66a0d551b..14f8c1617 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
+using CommonIO;
+using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Providers;
namespace MediaBrowser.Controller.Entities
@@ -62,7 +64,7 @@ namespace MediaBrowser.Controller.Entities
public List<string> PhysicalLocationsList { get; set; }
- protected override IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService).FileSystemChildren;
}
@@ -73,7 +75,7 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService)
{
- FileInfo = new DirectoryInfo(path),
+ FileInfo = FileSystem.GetDirectoryInfo(path),
Path = path,
Parent = Parent
};
@@ -94,7 +96,7 @@ namespace MediaBrowser.Controller.Entities
{
var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys);
- fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+ fileSystemDictionary = paths.Select(FileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
}
args.FileSystemDictionary = fileSystemDictionary;
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 623329ca6..43b980c20 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -24,14 +24,20 @@ namespace MediaBrowser.Controller.Entities.Audio
IThemeMedia,
IArchivable
{
- public string FormatName { get; set; }
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
public List<string> Tags { get; set; }
- public ExtraType ExtraType { get; set; }
+ public ExtraType? ExtraType { get; set; }
- public bool IsThemeMedia { get; set; }
+ [IgnoreDataMember]
+ public bool IsThemeMedia
+ {
+ get
+ {
+ return ExtraType.HasValue && ExtraType.Value == Model.Entities.ExtraType.ThemeSong;
+ }
+ }
public Audio()
{
@@ -46,12 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
}
- /// <summary>
- /// Gets or sets a value indicating whether this instance has embedded image.
- /// </summary>
- /// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
- public bool HasEmbeddedImage { get; set; }
-
[IgnoreDataMember]
protected override bool SupportsOwnedItems
{
@@ -212,8 +212,7 @@ namespace MediaBrowser.Controller.Entities.Audio
Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
RunTimeTicks = i.RunTimeTicks,
Container = i.Container,
- Size = i.Size,
- Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList()
+ Size = i.Size
};
if (string.IsNullOrEmpty(info.Container))
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 594b5ca93..ec688bd9f 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -23,6 +23,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Controller.Entities
{
@@ -38,7 +39,6 @@ namespace MediaBrowser.Controller.Entities
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
LockedFields = new List<MetadataFields>();
ImageInfos = new List<ItemImageInfo>();
- Identities = new List<IItemIdentity>();
}
/// <summary>
@@ -56,12 +56,16 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops";
+ public string PreferredMetadataCountryCode { get; set; }
+ public string PreferredMetadataLanguage { get; set; }
+
public List<ItemImageInfo> ImageInfos { get; set; }
/// <summary>
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
+ [IgnoreDataMember]
public string ChannelId { get; set; }
[IgnoreDataMember]
@@ -121,6 +125,12 @@ namespace MediaBrowser.Controller.Entities
public Guid Id { get; set; }
/// <summary>
+ /// Gets or sets a value indicating whether this instance is hd.
+ /// </summary>
+ /// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
+ public bool? IsHD { get; set; }
+
+ /// <summary>
/// Return the id that should be used to key display prefs for this item.
/// Default is based on the type for everything except actual generic folders.
/// </summary>
@@ -162,6 +172,26 @@ namespace MediaBrowser.Controller.Entities
}
}
+ /// <summary>
+ /// Id of the program.
+ /// </summary>
+ [IgnoreDataMember]
+ public string ExternalId
+ {
+ get { return this.GetProviderId("ProviderExternalId"); }
+ set
+ {
+ this.SetProviderId("ProviderExternalId", value);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the etag.
+ /// </summary>
+ /// <value>The etag.</value>
+ [IgnoreDataMember]
+ public string ExternalEtag { get; set; }
+
[IgnoreDataMember]
public virtual bool IsHidden
{
@@ -183,7 +213,7 @@ namespace MediaBrowser.Controller.Entities
{
// Local trailer, special feature, theme video, etc.
// An item that belongs to another item but is not part of the Parent-Child tree
- return !IsFolder && Parent == null && LocationType == LocationType.FileSystem;
+ return !IsFolder && ParentId == Guid.Empty && LocationType == LocationType.FileSystem;
}
}
@@ -305,6 +335,9 @@ namespace MediaBrowser.Controller.Entities
public DateTime DateLastSaved { get; set; }
+ [IgnoreDataMember]
+ public DateTime DateLastRefreshed { get; set; }
+
/// <summary>
/// The logger
/// </summary>
@@ -331,30 +364,8 @@ namespace MediaBrowser.Controller.Entities
return Name;
}
- /// <summary>
- /// Returns true if this item should not attempt to fetch metadata
- /// </summary>
- /// <value><c>true</c> if [dont fetch meta]; otherwise, <c>false</c>.</value>
- [Obsolete("Please use IsLocked instead of DontFetchMeta")]
- public bool DontFetchMeta { get; set; }
-
- [IgnoreDataMember]
- public bool IsLocked
- {
- get
- {
- return DontFetchMeta;
- }
- set
- {
- DontFetchMeta = value;
- }
- }
-
- public bool IsUnidentified { get; set; }
-
[IgnoreDataMember]
- public List<IItemIdentity> Identities { get; set; }
+ public bool IsLocked { get; set; }
/// <summary>
/// Gets or sets the locked fields.
@@ -484,7 +495,6 @@ namespace MediaBrowser.Controller.Entities
public Guid ParentId { get; set; }
- private Folder _parent;
/// <summary>
/// Gets or sets the parent.
/// </summary>
@@ -494,11 +504,6 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- if (_parent != null)
- {
- return _parent;
- }
-
if (ParentId != Guid.Empty)
{
return LibraryManager.GetItemById(ParentId) as Folder;
@@ -506,12 +511,14 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- set { _parent = value; }
+ set
+ {
+
+ }
}
public void SetParent(Folder parent)
{
- Parent = parent;
ParentId = parent == null ? Guid.Empty : parent.Id;
}
@@ -558,6 +565,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the end date.
/// </summary>
/// <value>The end date.</value>
+ [IgnoreDataMember]
public DateTime? EndDate { get; set; }
/// <summary>
@@ -582,6 +590,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the custom rating.
/// </summary>
/// <value>The custom rating.</value>
+ //[IgnoreDataMember]
public string CustomRating { get; set; }
/// <summary>
@@ -591,12 +600,6 @@ namespace MediaBrowser.Controller.Entities
public string Overview { get; set; }
/// <summary>
- /// Gets or sets the people.
- /// </summary>
- /// <value>The people.</value>
- public List<PersonInfo> People { get; set; }
-
- /// <summary>
/// Gets or sets the studios.
/// </summary>
/// <value>The studios.</value>
@@ -618,6 +621,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the community rating.
/// </summary>
/// <value>The community rating.</value>
+ //[IgnoreDataMember]
public float? CommunityRating { get; set; }
/// <summary>
@@ -643,6 +647,7 @@ namespace MediaBrowser.Controller.Entities
/// This could be episode number, album track number, etc.
/// </summary>
/// <value>The index number.</value>
+ //[IgnoreDataMember]
public int? IndexNumber { get; set; }
/// <summary>
@@ -662,7 +667,7 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- if (!string.IsNullOrEmpty(CustomRating))
+ if (!string.IsNullOrWhiteSpace(CustomRating))
{
return CustomRating;
}
@@ -701,16 +706,16 @@ namespace MediaBrowser.Controller.Entities
/// Loads the theme songs.
/// </summary>
/// <returns>List{Audio.Audio}.</returns>
- private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+ private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = fileSystemChildren.OfType<DirectoryInfo>()
+ var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
+ .SelectMany(i => directoryService.GetFiles(i.FullName))
.ToList();
// Support plex/xbmc convention
- files.AddRange(fileSystemChildren.OfType<FileInfo>()
- .Where(i => string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase))
+ files.AddRange(fileSystemChildren
+ .Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase))
);
return LibraryManager.ResolvePaths(files, directoryService, null)
@@ -737,11 +742,11 @@ namespace MediaBrowser.Controller.Entities
/// Loads the video backdrops.
/// </summary>
/// <returns>List{Video}.</returns>
- private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+ private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = fileSystemChildren.OfType<DirectoryInfo>()
+ var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly));
+ .SelectMany(i => directoryService.GetFiles(i.FullName));
return LibraryManager.ResolvePaths(files, directoryService, null)
.OfType<Video>()
@@ -765,7 +770,7 @@ namespace MediaBrowser.Controller.Entities
public Task RefreshMetadata(CancellationToken cancellationToken)
{
- return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService()), cancellationToken);
+ return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken);
}
/// <summary>
@@ -786,7 +791,7 @@ namespace MediaBrowser.Controller.Entities
{
var files = locationType != LocationType.Remote && locationType != LocationType.Virtual ?
GetFileSystemChildren(options.DirectoryService).ToList() :
- new List<FileSystemInfo>();
+ new List<FileSystemMetadata>();
var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false);
@@ -833,7 +838,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="fileSystemChildren"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
- protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var themeSongsChanged = false;
@@ -864,14 +869,14 @@ namespace MediaBrowser.Controller.Entities
return themeSongsChanged || themeVideosChanged || localTrailersChanged;
}
- protected virtual IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+ protected virtual IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
var path = ContainingFolderPath;
return directoryService.GetFileSystemEntries(path);
}
- private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList();
@@ -888,7 +893,7 @@ namespace MediaBrowser.Controller.Entities
return itemsChanged;
}
- private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
@@ -902,7 +907,7 @@ namespace MediaBrowser.Controller.Entities
if (!i.IsThemeMedia)
{
- i.IsThemeMedia = true;
+ i.ExtraType = ExtraType.ThemeVideo;
subOptions.ForceSave = true;
}
@@ -919,7 +924,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Refreshes the theme songs.
/// </summary>
- private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
@@ -932,7 +937,7 @@ namespace MediaBrowser.Controller.Entities
if (!i.IsThemeMedia)
{
- i.IsThemeMedia = true;
+ i.ExtraType = ExtraType.ThemeSong;
subOptions.ForceSave = true;
}
@@ -999,18 +1004,11 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public string GetPreferredMetadataLanguage()
{
- string lang = null;
-
- var hasLang = this as IHasPreferredMetadataLanguage;
-
- if (hasLang != null)
- {
- lang = hasLang.PreferredMetadataLanguage;
- }
+ string lang = PreferredMetadataLanguage;
if (string.IsNullOrWhiteSpace(lang))
{
- lang = Parents.OfType<IHasPreferredMetadataLanguage>()
+ lang = Parents
.Select(i => i.PreferredMetadataLanguage)
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
}
@@ -1036,18 +1034,11 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public string GetPreferredMetadataCountryCode()
{
- string lang = null;
-
- var hasLang = this as IHasPreferredMetadataLanguage;
-
- if (hasLang != null)
- {
- lang = hasLang.PreferredMetadataCountryCode;
- }
+ string lang = PreferredMetadataCountryCode;
if (string.IsNullOrWhiteSpace(lang))
{
- lang = Parents.OfType<IHasPreferredMetadataLanguage>()
+ lang = Parents
.Select(i => i.PreferredMetadataCountryCode)
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
}
@@ -1114,7 +1105,14 @@ namespace MediaBrowser.Controller.Entities
// Could not determine the integer value
if (!value.HasValue)
{
- return true;
+ var isAllowed = !GetBlockUnratedValue(user.Policy);
+
+ if (!isAllowed)
+ {
+ Logger.Debug("{0} has an unrecognized parental rating of {1}.", Name, rating);
+ }
+
+ return isAllowed;
}
return value.Value <= maxAllowedRating.Value;
@@ -1165,6 +1163,17 @@ namespace MediaBrowser.Controller.Entities
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
protected virtual bool GetBlockUnratedValue(UserPolicy config)
{
+ // Don't block plain folders that are unrated. Let the media underneath get blocked
+ // Special folders like series and albums will override this method.
+ if (IsFolder)
+ {
+ return false;
+ }
+ if (this is IItemByName)
+ {
+ return false;
+ }
+
return config.BlockUnratedItems.Contains(UnratedItem.Other);
}
@@ -1418,7 +1427,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Task.</returns>
public virtual Task ChangedExternally()
{
- ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions());
+ ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(FileSystem));
return Task.FromResult(true);
}
@@ -1434,7 +1443,24 @@ namespace MediaBrowser.Controller.Entities
return GetImageInfo(type, imageIndex) != null;
}
- public void SetImagePath(ImageType type, int index, FileSystemInfo file)
+ public void SetImage(ItemImageInfo image, int index)
+ {
+ if (image.Type == ImageType.Chapter)
+ {
+ throw new ArgumentException("Cannot set chapter images using SetImagePath");
+ }
+
+ var existingImage = GetImageInfo(image.Type, index);
+
+ if (existingImage != null)
+ {
+ ImageInfos.Remove(existingImage);
+ }
+
+ ImageInfos.Add(image);
+ }
+
+ public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
{
if (type == ImageType.Chapter)
{
@@ -1475,18 +1501,21 @@ namespace MediaBrowser.Controller.Entities
// Remove it from the item
RemoveImage(info);
- // Delete the source file
- var currentFile = new FileInfo(info.Path);
-
- // Deletion will fail if the file is hidden so remove the attribute first
- if (currentFile.Exists)
+ if (info.IsLocalFile)
{
- if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ // Delete the source file
+ var currentFile = new FileInfo(info.Path);
+
+ // Deletion will fail if the file is hidden so remove the attribute first
+ if (currentFile.Exists)
{
- currentFile.Attributes &= ~FileAttributes.Hidden;
- }
+ if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ {
+ currentFile.Attributes &= ~FileAttributes.Hidden;
+ }
- FileSystem.DeleteFile(currentFile.FullName);
+ FileSystem.DeleteFile(currentFile.FullName);
+ }
}
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
@@ -1507,11 +1536,16 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public bool ValidateImages(IDirectoryService directoryService)
{
- var allDirectories = ImageInfos.Select(i => System.IO.Path.GetDirectoryName(i.Path)).Distinct(StringComparer.OrdinalIgnoreCase).ToList();
- var allFiles = allDirectories.SelectMany(directoryService.GetFiles).Select(i => i.FullName).ToList();
+ var allFiles = ImageInfos
+ .Where(i => i.IsLocalFile)
+ .Select(i => System.IO.Path.GetDirectoryName(i.Path))
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .SelectMany(directoryService.GetFiles)
+ .Select(i => i.FullName)
+ .ToList();
var deletedImages = ImageInfos
- .Where(image => !allFiles.Contains(image.Path, StringComparer.OrdinalIgnoreCase))
+ .Where(image => image.IsLocalFile && !allFiles.Contains(image.Path, StringComparer.OrdinalIgnoreCase))
.ToList();
if (deletedImages.Count > 0)
@@ -1584,11 +1618,6 @@ namespace MediaBrowser.Controller.Entities
return ImageInfos.Where(i => i.Type == imageType);
}
- public bool AddImages(ImageType imageType, IEnumerable<FileInfo> images)
- {
- return AddImages(imageType, images.Cast<FileSystemInfo>().ToList());
- }
-
/// <summary>
/// Adds the images.
/// </summary>
@@ -1596,7 +1625,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="images">The images.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
/// <exception cref="System.ArgumentException">Cannot call AddImages with chapter images</exception>
- public bool AddImages(ImageType imageType, List<FileSystemInfo> images)
+ public bool AddImages(ImageType imageType, List<FileSystemMetadata> images)
{
if (imageType == ImageType.Chapter)
{
@@ -1606,7 +1635,7 @@ namespace MediaBrowser.Controller.Entities
var existingImages = GetImages(imageType)
.ToList();
- var newImageList = new List<FileSystemInfo>();
+ var newImageList = new List<FileSystemMetadata>();
var imageAdded = false;
foreach (var newImage in images)
@@ -1626,7 +1655,10 @@ namespace MediaBrowser.Controller.Entities
}
else
{
- existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
+ if (existing.IsLocalFile)
+ {
+ existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
+ }
}
}
@@ -1635,7 +1667,7 @@ namespace MediaBrowser.Controller.Entities
var newImagePaths = images.Select(i => i.FullName).ToList();
var deleted = existingImages
- .Where(i => !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !File.Exists(i.Path))
+ .Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path))
.ToList();
ImageInfos = ImageInfos.Except(deleted).ToList();
@@ -1646,7 +1678,7 @@ namespace MediaBrowser.Controller.Entities
return newImageList.Count > 0;
}
- private ItemImageInfo GetImageInfo(FileSystemInfo file, ImageType type)
+ private ItemImageInfo GetImageInfo(FileSystemMetadata file, ImageType type)
{
return new ItemImageInfo
{
@@ -1686,6 +1718,12 @@ namespace MediaBrowser.Controller.Entities
return Task.FromResult(true);
}
+ if (!info1.IsLocalFile || !info2.IsLocalFile)
+ {
+ // TODO: Not supported yet
+ return Task.FromResult(true);
+ }
+
var path1 = info1.Path;
var path2 = info2.Path;
@@ -1769,7 +1807,7 @@ namespace MediaBrowser.Controller.Entities
{
foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
{
- path = FileSystem.SubstitutePath(path, map.From, map.To);
+ path = LibraryManager.SubstitutePath(path, map.From, map.To);
}
}
@@ -1810,7 +1848,7 @@ namespace MediaBrowser.Controller.Entities
if (video == null)
{
- video = LibraryManager.ResolvePath(new FileInfo(path)) as Video;
+ video = LibraryManager.ResolvePath(FileSystem.GetFileSystemInfo(path)) as Video;
newOptions.ForceSave = true;
}
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index e59db67a6..d31675baf 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
- public class Book : BaseItem, IHasTags, IHasPreferredMetadataLanguage, IHasLookupInfo<BookInfo>, IHasSeries
+ public class Book : BaseItem, IHasTags, IHasLookupInfo<BookInfo>, IHasSeries
{
public override string MediaType
{
@@ -25,14 +25,6 @@ namespace MediaBrowser.Controller.Entities
public string SeriesName { get; set; }
- public string PreferredMetadataLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the preferred metadata country code.
- /// </summary>
- /// <value>The preferred metadata country code.</value>
- public string PreferredMetadataCountryCode { get; set; }
-
public Book()
{
Tags = new List<string>();
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 8821f35c8..946d95a0b 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -8,6 +8,8 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Entities
{
@@ -80,7 +82,7 @@ namespace MediaBrowser.Controller.Entities
public List<string> PhysicalLocationsList { get; set; }
- protected override IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService).FileSystemChildren;
}
@@ -107,7 +109,7 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
- FileInfo = new DirectoryInfo(path),
+ FileInfo = FileSystem.GetDirectoryInfo(path),
Path = path,
Parent = Parent,
CollectionType = CollectionType
@@ -129,7 +131,7 @@ namespace MediaBrowser.Controller.Entities
{
var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys);
- fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+ fileSystemDictionary = paths.Select(FileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
}
args.FileSystemDictionary = fileSystemDictionary;
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index c3ac77328..05965e1b5 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -13,13 +13,15 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Class Folder
/// </summary>
- public class Folder : BaseItem, IHasThemeMedia, IHasTags, IHasPreferredMetadataLanguage
+ public class Folder : BaseItem, IHasThemeMedia, IHasTags
{
public static IUserManager UserManager { get; set; }
public static IUserViewManager UserViewManager { get; set; }
@@ -28,14 +30,6 @@ namespace MediaBrowser.Controller.Entities
public List<Guid> ThemeVideoIds { get; set; }
public List<string> Tags { get; set; }
- public string PreferredMetadataLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the preferred metadata country code.
- /// </summary>
- /// <value>The preferred metadata country code.</value>
- public string PreferredMetadataCountryCode { get; set; }
-
public Folder()
{
LinkedChildren = new List<LinkedChild>();
@@ -48,7 +42,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public virtual bool IsPreSorted
{
- get { return ConfigurationManager.Configuration.EnableWindowsShortcuts; }
+ get { return false; }
}
/// <summary>
@@ -120,7 +114,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
protected virtual bool SupportsShortcutChildren
{
- get { return false; }
+ get { return ConfigurationManager.Configuration.EnableWindowsShortcuts; }
}
/// <summary>
@@ -213,7 +207,7 @@ namespace MediaBrowser.Controller.Entities
return base.OfficialRatingForComparison;
}
- return !string.IsNullOrEmpty(base.OfficialRatingForComparison) ? base.OfficialRatingForComparison : "None";
+ return !string.IsNullOrWhiteSpace(base.OfficialRatingForComparison) ? base.OfficialRatingForComparison : "None";
}
}
@@ -320,7 +314,7 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public IEnumerable<BaseItem> Children
{
- get { return ActualChildren; }
+ get { return ActualChildren.ToList(); }
}
/// <summary>
@@ -371,7 +365,7 @@ namespace MediaBrowser.Controller.Entities
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
{
- return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService()));
+ return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem)));
}
/// <summary>
@@ -474,7 +468,7 @@ namespace MediaBrowser.Controller.Entities
currentChild.DateModified = child.DateModified;
}
- currentChild.IsOffline = false;
+ await UpdateIsOffline(currentChild, false).ConfigureAwait(false);
validChildren.Add(currentChild);
}
else
@@ -509,12 +503,12 @@ namespace MediaBrowser.Controller.Entities
else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
{
- item.IsOffline = true;
+ await UpdateIsOffline(item, true).ConfigureAwait(false);
validChildren.Add(item);
}
else
{
- item.IsOffline = false;
+ await UpdateIsOffline(item, false).ConfigureAwait(false);
actualRemovals.Add(item);
}
}
@@ -569,6 +563,17 @@ namespace MediaBrowser.Controller.Entities
progress.Report(100);
}
+ private Task UpdateIsOffline(BaseItem item, bool newValue)
+ {
+ if (item.IsOffline != newValue)
+ {
+ item.IsOffline = newValue;
+ return item.UpdateToRepository(ItemUpdateType.None, CancellationToken.None);
+ }
+
+ return Task.FromResult(true);
+ }
+
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
{
var children = ActualChildren.ToList();
@@ -691,9 +696,9 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if the specified path is offline; otherwise, <c>false</c>.</returns>
- private bool IsPathOffline(string path)
+ public static bool IsPathOffline(string path)
{
- if (File.Exists(path))
+ if (FileSystem.FileExists(path))
{
return false;
}
@@ -703,7 +708,7 @@ namespace MediaBrowser.Controller.Entities
// Depending on whether the path is local or unc, it may return either null or '\' at the top
while (!string.IsNullOrEmpty(path) && path.Length > 1)
{
- if (Directory.Exists(path))
+ if (FileSystem.DirectoryExists(path))
{
return false;
}
@@ -725,12 +730,12 @@ namespace MediaBrowser.Controller.Entities
/// <param name="folders">The folders.</param>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if the specified folders contains path; otherwise, <c>false</c>.</returns>
- private bool ContainsPath(IEnumerable<VirtualFolderInfo> folders, string path)
+ private static bool ContainsPath(IEnumerable<VirtualFolderInfo> folders, string path)
{
return folders.SelectMany(i => i.Locations).Any(i => ContainsPath(i, path));
}
- private bool ContainsPath(string parent, string path)
+ private static bool ContainsPath(string parent, string path)
{
return string.Equals(parent, path, StringComparison.OrdinalIgnoreCase) || FileSystem.ContainsSubPath(parent, path);
}
@@ -752,21 +757,24 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IEnumerable{BaseItem}.</returns>
protected IEnumerable<BaseItem> GetCachedChildren()
{
- var childrenItems = ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
-
- //var children = ItemRepository.GetChildren(Id).Select(RetrieveChild).Where(i => i != null).ToList();
-
- //if (children.Count != childrenItems.Count)
- //{
- // var b = this;
- //}
+ if (ConfigurationManager.Configuration.DisableStartupScan)
+ {
+ return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
+ //return ItemRepository.GetItems(new InternalItemsQuery
+ //{
+ // ParentId = Id
- return childrenItems;
+ //}).Items.Select(RetrieveChild).Where(i => i != null);
+ }
+ else
+ {
+ return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
+ }
}
private BaseItem RetrieveChild(BaseItem child)
{
- if (child.Id == Guid.Empty)
+ if (child == null || child.Id == Guid.Empty)
{
Logger.Error("Item found with empty Id: " + (child.Path ?? child.Name));
return null;
@@ -1064,7 +1072,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var changesFound = false;
@@ -1085,7 +1093,7 @@ namespace MediaBrowser.Controller.Entities
/// Refreshes the linked children.
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool RefreshLinkedChildren(IEnumerable<FileSystemInfo> fileSystemChildren)
+ private bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
@@ -1170,9 +1178,16 @@ namespace MediaBrowser.Controller.Entities
DateTime? datePlayed,
bool resetPosition)
{
+ var itemsResult = await GetItems(new InternalItemsQuery
+ {
+ User = user,
+ Recursive = true,
+ IsFolder = false
+
+ }).ConfigureAwait(false);
+
// Sweep through recursively and update status
- var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
- .Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
+ var tasks = itemsResult.Items.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
@@ -1184,9 +1199,16 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Task.</returns>
public override async Task MarkUnplayed(User user)
{
+ var itemsResult = await GetItems(new InternalItemsQuery
+ {
+ User = user,
+ Recursive = true,
+ IsFolder = false
+
+ }).ConfigureAwait(false);
+
// Sweep through recursively and update status
- var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual)
- .Select(c => c.MarkUnplayed(user));
+ var tasks = itemsResult.Items.Select(c => c.MarkUnplayed(user));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index 15d2d755a..ed3e85d58 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -8,19 +8,11 @@ using System.Linq;
namespace MediaBrowser.Controller.Entities
{
- public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, ISupportsPlaceHolders, IHasPreferredMetadataLanguage, IHasLookupInfo<GameInfo>
+ public class Game : BaseItem, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo>
{
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
- public string PreferredMetadataLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the preferred metadata country code.
- /// </summary>
- /// <value>The preferred metadata country code.</value>
- public string PreferredMetadataCountryCode { get; set; }
-
public Game()
{
MultiPartGameFiles = new List<string>();
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
index ffb351c94..28835168a 100644
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ b/MediaBrowser.Controller/Entities/IHasImages.cs
@@ -2,7 +2,11 @@
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Entities
{
@@ -67,7 +71,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="type">The type.</param>
/// <param name="index">The index.</param>
/// <param name="file">The file.</param>
- void SetImagePath(ImageType type, int index, FileSystemInfo file);
+ void SetImagePath(ImageType type, int index, FileSystemMetadata file);
/// <summary>
/// Determines whether the specified type has image.
@@ -134,7 +138,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="imageType">Type of the image.</param>
/// <param name="images">The images.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AddImages(ImageType imageType, List<FileSystemInfo> images);
+ bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
/// <summary>
/// Determines whether [is save local metadata enabled].
@@ -189,6 +193,21 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="image">The image.</param>
void RemoveImage(ItemImageInfo image);
+
+ /// <summary>
+ /// Updates to repository.
+ /// </summary>
+ /// <param name="updateReason">The update reason.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sets the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ /// <param name="index">The index.</param>
+ void SetImage(ItemImageInfo image, int index);
}
public static class HasImagesExtensions
@@ -215,7 +234,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <param name="file">The file.</param>
- public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemInfo file)
+ public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemMetadata file)
{
item.SetImagePath(imageType, 0, file);
}
@@ -228,7 +247,18 @@ namespace MediaBrowser.Controller.Entities
/// <param name="file">The file.</param>
public static void SetImagePath(this IHasImages item, ImageType imageType, string file)
{
- item.SetImagePath(imageType, new FileInfo(file));
+ if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
+ {
+ item.SetImage(new ItemImageInfo
+ {
+ Path = file,
+ Type = imageType
+ }, 0);
+ }
+ else
+ {
+ item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs
index 158bcb6d1..473ee120e 100644
--- a/MediaBrowser.Controller/Entities/IHasMetadata.cs
+++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs
@@ -31,13 +31,11 @@ namespace MediaBrowser.Controller.Entities
DateTime DateLastSaved { get; set; }
/// <summary>
- /// Updates to repository.
+ /// Gets or sets the date last refreshed.
/// </summary>
- /// <param name="updateReason">The update reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
-
+ /// <value>The date last refreshed.</value>
+ DateTime DateLastRefreshed { get; set; }
+
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made
/// </summary>
@@ -45,17 +43,6 @@ namespace MediaBrowser.Controller.Entities
bool BeforeMetadataRefresh();
/// <summary>
- /// Gets or sets a value indicating whether this instance is unidentified.
- /// </summary>
- /// <value><c>true</c> if this instance is unidentified; otherwise, <c>false</c>.</value>
- bool IsUnidentified { get; set; }
-
- /// <summary>
- /// Gets the item identities.
- /// </summary>
- List<IItemIdentity> Identities { get; set; }
-
- /// <summary>
/// Afters the metadata refresh.
/// </summary>
void AfterMetadataRefresh();
diff --git a/MediaBrowser.Controller/Entities/IHasPreferredMetadataLanguage.cs b/MediaBrowser.Controller/Entities/IHasPreferredMetadataLanguage.cs
deleted file mode 100644
index e3a233e49..000000000
--- a/MediaBrowser.Controller/Entities/IHasPreferredMetadataLanguage.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-
-namespace MediaBrowser.Controller.Entities
-{
- /// <summary>
- /// Interface IHasPreferredMetadataLanguage
- /// </summary>
- public interface IHasPreferredMetadataLanguage
- {
- /// <summary>
- /// Gets or sets the preferred metadata language.
- /// </summary>
- /// <value>The preferred metadata language.</value>
- string PreferredMetadataLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the preferred metadata country code.
- /// </summary>
- /// <value>The preferred metadata country code.</value>
- string PreferredMetadataCountryCode { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
index 9938a4489..1c3270d72 100644
--- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
+++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs
@@ -15,6 +15,6 @@ namespace MediaBrowser.Controller.Entities
bool IsLive { get; set; }
bool IsPremiere { get; set; }
ProgramAudio? Audio { get; set; }
- DateTime? OriginalAirDate { get; set; }
+ string EpisodeTitle { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 0af4972f7..785e2fd2b 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -52,7 +52,6 @@ namespace MediaBrowser.Controller.Entities
public bool? IsHD { get; set; }
public bool? IsInBoxSet { get; set; }
public bool? IsLocked { get; set; }
- public bool? IsUnidentified { get; set; }
public bool? IsPlaceHolder { get; set; }
public bool? IsYearMismatched { get; set; }
@@ -98,7 +97,11 @@ namespace MediaBrowser.Controller.Entities
public bool? IsCurrentSchema { get; set; }
public bool? HasDeadParentId { get; set; }
-
+ public bool? IsOffline { get; set; }
+ public LocationType? LocationType { get; set; }
+
+ public Guid? ParentId { get; set; }
+
public InternalItemsQuery()
{
Tags = new string[] { };
diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
index b36b818ff..bb113e596 100644
--- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs
+++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Model.Entities;
using System;
+using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -22,5 +23,21 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The date modified.</value>
public DateTime DateModified { get; set; }
+
+ [IgnoreDataMember]
+ public bool IsLocalFile
+ {
+ get
+ {
+ if (Path != null)
+ {
+ if (Path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 083ec0cb4..1a8148edf 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -8,6 +8,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -122,7 +124,7 @@ namespace MediaBrowser.Controller.Entities.Movies
return key;
}
- protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -141,7 +143,7 @@ namespace MediaBrowser.Controller.Entities.Movies
return hasChanges;
}
- private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
var newItemIds = newItems.Select(i => i.Id).ToList();
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 5163c3de4..92ca9e970 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -296,9 +296,16 @@ namespace MediaBrowser.Controller.Entities.TV
{
var hasChanges = base.BeforeMetadataRefresh();
- if (LibraryManager.FillMissingEpisodeNumbersFromPath(this))
+ try
{
- hasChanges = true;
+ if (LibraryManager.FillMissingEpisodeNumbersFromPath(this))
+ {
+ hasChanges = true;
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error in FillMissingEpisodeNumbersFromPath. Episode: {0}", ex, Path ?? Name ?? Id.ToString());
}
return hasChanges;
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index cfd6b46e0..21b89d7a9 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -62,17 +62,13 @@ namespace MediaBrowser.Controller.Entities.TV
}
/// <summary>
- /// The _series
- /// </summary>
- private Series _series;
- /// <summary>
/// This Episode's Series Instance
/// </summary>
/// <value>The series.</value>
[IgnoreDataMember]
public Series Series
{
- get { return _series ?? (_series = FindParent<Series>()); }
+ get { return FindParent<Series>(); }
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 2663d19e8..b23833845 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -20,7 +20,6 @@ namespace MediaBrowser.Controller.Entities.TV
public List<Guid> SpecialFeatureIds { get; set; }
public string OriginalTitle { get; set; }
- public int SeasonCount { get; set; }
public int? AnimeSeriesIndex { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index f44128e2d..6ec512783 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.Controller.Entities
{
@@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.Entities
protected override string CreateUserDataKey()
{
- var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb);
+ var key = Movie.GetMovieUserDataKey(this);
if (!string.IsNullOrWhiteSpace(key))
{
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 71e3d1ce0..a9e314ede 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.Entities
{
public static IUserManager UserManager { get; set; }
public static IXmlSerializer XmlSerializer { get; set; }
+ public bool EnableUserViews { get; set; }
/// <summary>
/// From now on all user paths will be Id-based.
@@ -177,24 +178,24 @@ namespace MediaBrowser.Controller.Entities
var oldConfigurationDirectory = ConfigurationDirectoryPath;
// Exceptions will be thrown if these paths already exist
- if (Directory.Exists(newConfigDirectory))
+ if (FileSystem.DirectoryExists(newConfigDirectory))
{
FileSystem.DeleteDirectory(newConfigDirectory, true);
}
- if (Directory.Exists(oldConfigurationDirectory))
+ if (FileSystem.DirectoryExists(oldConfigurationDirectory))
{
- Directory.Move(oldConfigurationDirectory, newConfigDirectory);
+ FileSystem.MoveDirectory(oldConfigurationDirectory, newConfigDirectory);
}
else
{
- Directory.CreateDirectory(newConfigDirectory);
+ FileSystem.CreateDirectory(newConfigDirectory);
}
}
Name = newName;
- return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService())
+ return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem))
{
ReplaceAllMetadata = true,
ImageRefreshMode = ImageRefreshMode.FullRefresh,
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 488e54cc3..5ee49ae5a 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -13,6 +13,7 @@ namespace MediaBrowser.Controller.Entities
{
public string ViewType { get; set; }
public Guid ParentId { get; set; }
+ public Guid DisplayParentId { get; set; }
public Guid? UserId { get; set; }
@@ -28,7 +29,11 @@ namespace MediaBrowser.Controller.Entities
{
var parent = this as Folder;
- if (ParentId != Guid.Empty)
+ if (DisplayParentId != Guid.Empty)
+ {
+ parent = LibraryManager.GetItemById(DisplayParentId) as Folder ?? parent;
+ }
+ else if (ParentId != Guid.Empty)
{
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
@@ -82,7 +87,28 @@ namespace MediaBrowser.Controller.Entities
{
CollectionType.Books,
CollectionType.HomeVideos,
- CollectionType.Photos
+ CollectionType.Photos,
+ CollectionType.Playlists,
+ CollectionType.BoxSets,
+ CollectionType.MusicVideos
+ };
+
+ var collectionFolder = folder as ICollectionFolder;
+
+ if (collectionFolder == null)
+ {
+ return false;
+ }
+
+ return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty);
+ }
+
+ public static bool IsUserSpecific(Folder folder)
+ {
+ var standaloneTypes = new List<string>
+ {
+ CollectionType.Playlists,
+ CollectionType.BoxSets
};
var collectionFolder = folder as ICollectionFolder;
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index cee5dadd2..f5800ce81 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -577,19 +577,9 @@ namespace MediaBrowser.Controller.Entities
private async Task<QueryResult<BaseItem>> GetBoxsetView(Folder parent, User user, InternalItemsQuery query)
{
- return GetResult(GetMediaFolders(user).SelectMany(i =>
- {
- var hasCollectionType = i as ICollectionFolder;
- Func<BaseItem, bool> filter = b => b is BoxSet;
-
- if (hasCollectionType != null && string.Equals(hasCollectionType.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
- {
- return i.GetChildren(user, true).Where(filter);
- }
-
- return i.GetRecursiveChildren(user, filter);
+ var collections = _collectionManager.GetCollections(user);
- }), parent, query);
+ return GetResult(collections, parent, query);
}
private async Task<QueryResult<BaseItem>> GetPhotosView(Folder queryParent, User user, InternalItemsQuery query)
@@ -1041,11 +1031,6 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (request.IsUnidentified.HasValue)
- {
- return false;
- }
-
if (request.IsYearMismatched.HasValue)
{
return false;
@@ -1412,16 +1397,7 @@ namespace MediaBrowser.Controller.Entities
var val = query.IsHD.Value;
var video = item as Video;
- if (video == null || val != video.IsHD)
- {
- return false;
- }
- }
-
- if (query.IsUnidentified.HasValue)
- {
- var val = query.IsUnidentified.Value;
- if (item.IsUnidentified != val)
+ if (video == null || !video.IsHD.HasValue || val != video.IsHD)
{
return false;
}
@@ -1808,6 +1784,13 @@ namespace MediaBrowser.Controller.Entities
private IEnumerable<Folder> GetMediaFolders(User user)
{
+ if (user == null)
+ {
+ return _libraryManager.RootFolder
+ .Children
+ .OfType<Folder>()
+ .Where(i => !UserView.IsExcludedFromGrouping(i));
+ }
return user.RootFolder
.GetChildren(user, true, true)
.OfType<Folder>()
@@ -1816,6 +1799,16 @@ namespace MediaBrowser.Controller.Entities
private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
{
+ if (user == null)
+ {
+ return GetMediaFolders(null)
+ .Where(i =>
+ {
+ var folder = i as ICollectionFolder;
+
+ return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ });
+ }
return GetMediaFolders(user)
.Where(i =>
{
@@ -1839,9 +1832,19 @@ namespace MediaBrowser.Controller.Entities
{
if (parent == null || parent is UserView)
{
+ if (user == null)
+ {
+ return GetMediaFolders(null, viewTypes).SelectMany(i => i.GetRecursiveChildren());
+ }
+
return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
}
+ if (user == null)
+ {
+ return parent.GetRecursiveChildren();
+ }
+
return parent.GetRecursiveChildren(user);
}
@@ -1849,9 +1852,19 @@ namespace MediaBrowser.Controller.Entities
{
if (parent == null || parent is UserView)
{
+ if (user == null)
+ {
+ return GetMediaFolders(null, viewTypes).SelectMany(i => i.GetRecursiveChildren(filter));
+ }
+
return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user, filter));
}
+ if (user == null)
+ {
+ return parent.GetRecursiveChildren(filter);
+ }
+
return parent.GetRecursiveChildren(user, filter);
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 00dc5dc67..8beee79bf 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -11,6 +11,8 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Entities
{
@@ -23,7 +25,6 @@ namespace MediaBrowser.Controller.Entities
ISupportsPlaceHolders,
IHasMediaSources,
IHasShortOverview,
- IHasPreferredMetadataLanguage,
IThemeMedia,
IArchivable
{
@@ -33,21 +34,20 @@ namespace MediaBrowser.Controller.Entities
public List<string> LocalAlternateVersions { get; set; }
public List<LinkedChild> LinkedAlternateVersions { get; set; }
- public bool IsThemeMedia { get; set; }
+ [IgnoreDataMember]
+ public bool IsThemeMedia
+ {
+ get
+ {
+ return ExtraType.HasValue && ExtraType.Value == Model.Entities.ExtraType.ThemeVideo;
+ }
+ }
- public string FormatName { get; set; }
public long? Size { get; set; }
public string Container { get; set; }
public int? TotalBitrate { get; set; }
public string ShortOverview { get; set; }
- public ExtraType ExtraType { get; set; }
-
- /// <summary>
- /// Gets or sets the preferred metadata country code.
- /// </summary>
- /// <value>The preferred metadata country code.</value>
- public string PreferredMetadataCountryCode { get; set; }
- public string PreferredMetadataLanguage { get; set; }
+ public ExtraType? ExtraType { get; set; }
/// <summary>
/// Gets or sets the timestamp.
@@ -313,7 +313,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>List{System.String}.</returns>
public List<string> GetPlayableStreamFiles(string rootPath)
{
- var allFiles = Directory.EnumerateFiles(rootPath, "*", SearchOption.AllDirectories).ToList();
+ var allFiles = FileSystem.GetFilePaths(rootPath, true).ToList();
return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
.Where(f => !string.IsNullOrEmpty(f))
@@ -330,8 +330,6 @@ namespace MediaBrowser.Controller.Entities
get { return Video3DFormat.HasValue; }
}
- public bool IsHD { get; set; }
-
/// <summary>
/// Gets the type of the media.
/// </summary>
@@ -345,7 +343,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+ protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -498,7 +496,6 @@ namespace MediaBrowser.Controller.Entities
VideoType = i.VideoType,
Container = i.Container,
Size = i.Size,
- Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
Timestamp = i.Timestamp,
Type = type,
PlayableStreamFileNames = i.PlayableStreamFileNames.ToList(),
diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs
index fb0f07331..20dfc425e 100644
--- a/MediaBrowser.Controller/IO/FileData.cs
+++ b/MediaBrowser.Controller/IO/FileData.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
+using CommonIO;
namespace MediaBrowser.Controller.IO
{
@@ -25,7 +26,7 @@ namespace MediaBrowser.Controller.IO
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
/// <exception cref="System.ArgumentNullException">path</exception>
- public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(IDirectoryService directoryService,
+ public static Dictionary<string, FileSystemMetadata> GetFilteredFileSystemEntries(IDirectoryService directoryService,
string path,
IFileSystem fileSystem,
ILogger logger,
@@ -49,7 +50,7 @@ namespace MediaBrowser.Controller.IO
var entries = directoryService.GetFileSystemEntries(path);
- var dict = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase);
+ var dict = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in entries)
{
@@ -69,7 +70,7 @@ namespace MediaBrowser.Controller.IO
}
// Don't check if it exists here because that could return false for network shares.
- var data = new DirectoryInfo(newPath);
+ var data = fileSystem.GetDirectoryInfo(newPath);
// add to our physical locations
args.AddAdditionalLocation(newPath);
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index d202e221e..1b842a5f6 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -24,6 +24,12 @@ namespace MediaBrowser.Controller
bool SupportsAutoRunAtStartup { get; }
/// <summary>
+ /// Gets a value indicating whether [supports library monitor].
+ /// </summary>
+ /// <value><c>true</c> if [supports library monitor]; otherwise, <c>false</c>.</value>
+ bool SupportsLibraryMonitor { get; }
+
+ /// <summary>
/// Gets the HTTP server port.
/// </summary>
/// <value>The HTTP server port.</value>
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 9331ca759..c7ab88524 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Library
{
@@ -25,19 +27,18 @@ namespace MediaBrowser.Controller.Library
/// <param name="fileInfo">The file information.</param>
/// <param name="parent">The parent.</param>
/// <returns>BaseItem.</returns>
- BaseItem ResolvePath(FileSystemInfo fileInfo,
+ BaseItem ResolvePath(FileSystemMetadata fileInfo,
Folder parent = null);
/// <summary>
/// Resolves a set of files into a list of BaseItem
/// </summary>
- /// <typeparam name="T"></typeparam>
/// <param name="files">The files.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="parent">The parent.</param>
/// <param name="collectionType">Type of the collection.</param>
/// <returns>List{``0}.</returns>
- IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemInfo> files,
+ IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
IDirectoryService directoryService,
Folder parent, string
collectionType = null);
@@ -385,6 +386,21 @@ namespace MediaBrowser.Controller.Library
CancellationToken cancellationToken);
/// <summary>
+ /// Gets the shadow view.
+ /// </summary>
+ /// <param name="parent">The parent.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ /// <param name="uniqueId">The unique identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;UserView&gt;.</returns>
+ Task<UserView> GetShadowView(BaseItem parent,
+ string viewType,
+ string sortName,
+ string uniqueId,
+ CancellationToken cancellationToken);
+
+ /// <summary>
/// Determines whether [is video file] [the specified path].
/// </summary>
/// <param name="path">The path.</param>
@@ -434,7 +450,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="fileSystemChildren">The file system children.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>IEnumerable&lt;Trailer&gt;.</returns>
- IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemInfo> fileSystemChildren,
+ IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
IDirectoryService directoryService);
/// <summary>
@@ -444,7 +460,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="fileSystemChildren">The file system children.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>IEnumerable&lt;Video&gt;.</returns>
- IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren,
+ IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
IDirectoryService directoryService);
/// <summary>
@@ -509,5 +525,23 @@ namespace MediaBrowser.Controller.Library
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
+
+ /// <summary>
+ /// Substitutes the path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="from">From.</param>
+ /// <param name="to">To.</param>
+ /// <returns>System.String.</returns>
+ string SubstitutePath(string path, string from, string to);
+
+ /// <summary>
+ /// Converts the image to local.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="image">The image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>Task.</returns>
+ Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index db441d285..90158942f 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Library
{
@@ -35,7 +37,7 @@ namespace MediaBrowser.Controller.Library
/// Gets the file system children.
/// </summary>
/// <value>The file system children.</value>
- public IEnumerable<FileSystemInfo> FileSystemChildren
+ public IEnumerable<FileSystemMetadata> FileSystemChildren
{
get
{
@@ -43,7 +45,7 @@ namespace MediaBrowser.Controller.Library
if (dict == null)
{
- return new List<FileSystemInfo>();
+ return new List<FileSystemMetadata>();
}
return dict.Values;
@@ -54,7 +56,7 @@ namespace MediaBrowser.Controller.Library
/// Gets or sets the file system dictionary.
/// </summary>
/// <value>The file system dictionary.</value>
- public Dictionary<string, FileSystemInfo> FileSystemDictionary { get; set; }
+ public Dictionary<string, FileSystemMetadata> FileSystemDictionary { get; set; }
/// <summary>
/// Gets or sets the parent.
@@ -66,7 +68,7 @@ namespace MediaBrowser.Controller.Library
/// Gets or sets the file info.
/// </summary>
/// <value>The file info.</value>
- public FileSystemInfo FileInfo { get; set; }
+ public FileSystemMetadata FileInfo { get; set; }
/// <summary>
/// Gets or sets the path.
@@ -201,7 +203,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="name">The name.</param>
/// <returns>FileSystemInfo.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- public FileSystemInfo GetFileSystemEntryByName(string name)
+ public FileSystemMetadata GetFileSystemEntryByName(string name)
{
if (string.IsNullOrEmpty(name))
{
@@ -217,7 +219,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="path">The path.</param>
/// <returns>FileSystemInfo.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- public FileSystemInfo GetFileSystemEntryByPath(string path)
+ public FileSystemMetadata GetFileSystemEntryByPath(string path)
{
if (string.IsNullOrEmpty(path))
{
@@ -226,7 +228,7 @@ namespace MediaBrowser.Controller.Library
if (FileSystemDictionary != null)
{
- FileSystemInfo entry;
+ FileSystemMetadata entry;
if (FileSystemDictionary.TryGetValue(path, out entry))
{
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
index e60183bd9..f5048bdda 100644
--- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.LiveTv
{
string Name { get; }
string Type { get; }
- Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
+ Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 1458c1bc2..241b01405 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -338,8 +338,9 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <param name="item">The item.</param>
/// <param name="dto">The dto.</param>
+ /// <param name="addChannelInfo">if set to <c>true</c> [add channel information].</param>
/// <param name="user">The user.</param>
- void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null);
+ void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, bool addChannelInfo, User user = null);
/// <summary>
/// Saves the tuner host.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
index ba0b82a0b..5dc5f68cd 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.LiveTv
public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, ILiveTvItem, IHasStartDate, IHasProgramAttributes
{
string ChannelId { get; }
- string ProgramId { get; set; }
string MediaType { get; }
string Container { get; }
@@ -31,16 +30,9 @@ namespace MediaBrowser.Controller.LiveTv
bool CanDelete(User user);
- string ProviderImagePath { get; set; }
-
- string ProviderImageUrl { get; set; }
-
- string ExternalId { get; set; }
- string EpisodeTitle { get; set; }
string SeriesTimerId { get; set; }
RecordingStatus Status { get; set; }
DateTime? EndDate { get; set; }
- ChannelType ChannelType { get; set; }
DateTime DateLastSaved { get; set; }
DateTime DateCreated { get; set; }
DateTime DateModified { get; set; }
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index bedbcffe3..2e3a71f70 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Dto;
+using System;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System.Collections.Generic;
using System.Threading;
@@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="streamId">The stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
- Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
+ Task<Tuple<MediaSourceInfo,SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel stream media sources.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
index 2179c5ecd..03c05ec69 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -14,26 +14,29 @@ namespace MediaBrowser.Controller.LiveTv
{
public class LiveTvAudioRecording : Audio, ILiveTvRecording
{
- public string ExternalId { get; set; }
- public string ProviderImagePath { get; set; }
- public string ProviderImageUrl { get; set; }
+ [IgnoreDataMember]
public string EpisodeTitle { get; set; }
+ [IgnoreDataMember]
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
+ [IgnoreDataMember]
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
+ [IgnoreDataMember]
public bool IsSports { get; set; }
+ [IgnoreDataMember]
public bool IsNews { get; set; }
+ [IgnoreDataMember]
public bool IsKids { get; set; }
+ [IgnoreDataMember]
public bool IsRepeat { get; set; }
+ [IgnoreDataMember]
public bool IsMovie { get; set; }
- public bool? IsHD { get; set; }
+ [IgnoreDataMember]
public bool IsLive { get; set; }
+ [IgnoreDataMember]
public bool IsPremiere { get; set; }
- public ChannelType ChannelType { get; set; }
- public string ProgramId { get; set; }
public ProgramAudio? Audio { get; set; }
- public DateTime? OriginalAirDate { get; set; }
/// <summary>
/// Gets the user data key.
@@ -43,11 +46,6 @@ namespace MediaBrowser.Controller.LiveTv
{
var name = GetClientTypeName();
- if (!string.IsNullOrEmpty(ProgramId))
- {
- return name + "-" + ProgramId;
- }
-
return name + "-" + Name + (EpisodeTitle ?? string.Empty);
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index cb10003ed..89168c578 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -47,12 +47,6 @@ namespace MediaBrowser.Controller.LiveTv
public string Number { get; set; }
/// <summary>
- /// Gets or sets the external identifier.
- /// </summary>
- /// <value>The external identifier.</value>
- public string ExternalId { get; set; }
-
- /// <summary>
/// Gets or sets the type of the channel.
/// </summary>
/// <value>The type of the channel.</value>
@@ -64,24 +58,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The name of the service.</value>
public string ServiceName { get; set; }
- /// <summary>
- /// Supply the image path if it can be accessed directly from the file system
- /// </summary>
- /// <value>The image path.</value>
- public string ProviderImagePath { get; set; }
-
- /// <summary>
- /// Supply the image url if it can be downloaded
- /// </summary>
- /// <value>The image URL.</value>
- public string ProviderImageUrl { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has image.
- /// </summary>
- /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
- public bool? HasProviderImage { get; set; }
-
+ [IgnoreDataMember]
public override LocationType LocationType
{
get
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 12052905f..e4b52fd99 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Users;
using System;
using System.Linq;
using System.Runtime.Serialization;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.LiveTv
{
@@ -31,23 +32,6 @@ namespace MediaBrowser.Controller.LiveTv
}
/// <summary>
- /// Gets or sets the etag.
- /// </summary>
- /// <value>The etag.</value>
- public string Etag { get; set; }
-
- /// <summary>
- /// Id of the program.
- /// </summary>
- public string ExternalId { get; set; }
-
- /// <summary>
- /// Gets or sets the original air date.
- /// </summary>
- /// <value>The original air date.</value>
- public DateTime? OriginalAirDate { get; set; }
-
- /// <summary>
/// Gets or sets the type of the channel.
/// </summary>
/// <value>The type of the channel.</value>
@@ -56,15 +40,10 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary>
/// The start date of the program, in UTC.
/// </summary>
+ [IgnoreDataMember]
public DateTime StartDate { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether this instance is hd.
- /// </summary>
- /// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
- public bool? IsHD { get; set; }
-
- /// <summary>
/// Gets or sets the audio.
/// </summary>
/// <value>The audio.</value>
@@ -74,12 +53,14 @@ namespace MediaBrowser.Controller.LiveTv
/// Gets or sets a value indicating whether this instance is repeat.
/// </summary>
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsRepeat { get; set; }
/// <summary>
/// Gets or sets the episode title.
/// </summary>
/// <value>The episode title.</value>
+ [IgnoreDataMember]
public string EpisodeTitle { get; set; }
/// <summary>
@@ -89,63 +70,52 @@ namespace MediaBrowser.Controller.LiveTv
public string ServiceName { get; set; }
/// <summary>
- /// Supply the image path if it can be accessed directly from the file system
- /// </summary>
- /// <value>The image path.</value>
- public string ProviderImagePath { get; set; }
-
- /// <summary>
- /// Supply the image url if it can be downloaded
- /// </summary>
- /// <value>The image URL.</value>
- public string ProviderImageUrl { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has image.
- /// </summary>
- /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
- public bool? HasProviderImage { get; set; }
-
- /// <summary>
/// Gets or sets a value indicating whether this instance is movie.
/// </summary>
/// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsMovie { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsSports { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
/// </summary>
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsSeries { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsLive { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsNews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsKids { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is premiere.
/// </summary>
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
public bool IsPremiere { get; set; }
/// <summary>
@@ -244,6 +214,7 @@ namespace MediaBrowser.Controller.LiveTv
return info;
}
+ [IgnoreDataMember]
public override bool SupportsPeople
{
get
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index 960f8054a..77404cfe8 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -14,26 +14,29 @@ namespace MediaBrowser.Controller.LiveTv
{
public class LiveTvVideoRecording : Video, ILiveTvRecording
{
- public string ExternalId { get; set; }
- public string ProviderImagePath { get; set; }
- public string ProviderImageUrl { get; set; }
+ [IgnoreDataMember]
public string EpisodeTitle { get; set; }
+ [IgnoreDataMember]
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
+ [IgnoreDataMember]
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
+ [IgnoreDataMember]
public bool IsSports { get; set; }
+ [IgnoreDataMember]
public bool IsNews { get; set; }
+ [IgnoreDataMember]
public bool IsKids { get; set; }
+ [IgnoreDataMember]
public bool IsRepeat { get; set; }
+ [IgnoreDataMember]
public bool IsMovie { get; set; }
- public bool? IsHD { get; set; }
+ [IgnoreDataMember]
public bool IsLive { get; set; }
+ [IgnoreDataMember]
public bool IsPremiere { get; set; }
- public ChannelType ChannelType { get; set; }
- public string ProgramId { get; set; }
public ProgramAudio? Audio { get; set; }
- public DateTime? OriginalAirDate { get; set; }
/// <summary>
/// Gets the user data key.
@@ -53,11 +56,6 @@ namespace MediaBrowser.Controller.LiveTv
var name = GetClientTypeName();
- if (!string.IsNullOrEmpty(ProgramId))
- {
- return name + "-" + ProgramId;
- }
-
return name + "-" + Name + (EpisodeTitle ?? string.Empty);
}
@@ -109,6 +107,7 @@ namespace MediaBrowser.Controller.LiveTv
return false;
}
+ [IgnoreDataMember]
public override bool SupportsLocalMetadata
{
get
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 24309734f..bcf4de2a2 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -11,10 +11,9 @@
<AssemblyName>MediaBrowser.Controller</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
+ <ReleaseVersion>
+ </ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -24,7 +23,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -33,7 +31,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
@@ -45,15 +42,17 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="Interfaces.IO">
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -66,6 +65,9 @@
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
</Reference>
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -81,7 +83,6 @@
<Compile Include="Channels\ChannelParentalRating.cs" />
<Compile Include="Channels\ChannelSearchInfo.cs" />
<Compile Include="Channels\IChannel.cs" />
- <Compile Include="Channels\IChannelFactory.cs" />
<Compile Include="Channels\IChannelManager.cs" />
<Compile Include="Channels\IChannelItem.cs" />
<Compile Include="Channels\ChannelAudioItem.cs" />
@@ -149,7 +150,6 @@
<Compile Include="Entities\IHasMediaSources.cs" />
<Compile Include="Entities\IHasMetascore.cs" />
<Compile Include="Entities\IHasOriginalTitle.cs" />
- <Compile Include="Entities\IHasPreferredMetadataLanguage.cs" />
<Compile Include="Entities\IHasProductionLocations.cs" />
<Compile Include="Entities\IHasProgramAttributes.cs" />
<Compile Include="Entities\IHasScreenshots.cs" />
@@ -273,7 +273,6 @@
<Compile Include="Providers\DirectoryService.cs" />
<Compile Include="Providers\DynamicImageInfo.cs" />
<Compile Include="Providers\DynamicImageResponse.cs" />
- <Compile Include="Providers\EpisodeIdentity.cs" />
<Compile Include="Providers\EpisodeInfo.cs" />
<Compile Include="Providers\ExtraInfo.cs" />
<Compile Include="Providers\ExtraSource.cs" />
@@ -287,14 +286,12 @@
<Compile Include="Providers\IForcedProvider.cs" />
<Compile Include="Providers\IHasChangeMonitor.cs" />
<Compile Include="Entities\IHasMetadata.cs" />
- <Compile Include="Providers\IHasIdentities.cs" />
<Compile Include="Providers\IHasItemChangeMonitor.cs" />
<Compile Include="Providers\IHasLookupInfo.cs" />
<Compile Include="Providers\IHasOrder.cs" />
<Compile Include="Providers\IImageFileSaver.cs" />
<Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Providers\IImageSaver.cs" />
- <Compile Include="Providers\IItemIdentity.cs" />
<Compile Include="Providers\IItemIdentityConverter.cs" />
<Compile Include="Providers\IItemIdentityProvider.cs" />
<Compile Include="Providers\ILocalImageFileProvider.cs" />
@@ -319,9 +316,7 @@
<Compile Include="Providers\MusicVideoInfo.cs" />
<Compile Include="Providers\PersonLookupInfo.cs" />
<Compile Include="Providers\RemoteSearchQuery.cs" />
- <Compile Include="Providers\SeasonIdentity.cs" />
<Compile Include="Providers\SeasonInfo.cs" />
- <Compile Include="Providers\SeriesIdentity.cs" />
<Compile Include="Providers\SeriesInfo.cs" />
<Compile Include="Providers\SeriesOrderTypes.cs" />
<Compile Include="Providers\SongInfo.cs" />
@@ -418,8 +413,6 @@
<Compile Include="Sync\ISyncRepository.cs" />
<Compile Include="Sync\SyncedFileInfo.cs" />
<Compile Include="Sync\SyncedItemProgress.cs" />
- <Compile Include="Themes\IAppThemeManager.cs" />
- <Compile Include="Themes\InternalThemeImage.cs" />
<Compile Include="TV\ITVSeriesManager.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 23285b612..427af6f6d 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -25,6 +25,13 @@ namespace MediaBrowser.Controller.MediaEncoding
string Version { get; }
/// <summary>
+ /// Supportses the decoder.
+ /// </summary>
+ /// <param name="decoder">The decoder.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool SupportsDecoder(string decoder);
+
+ /// <summary>
/// Extracts the audio image.
/// </summary>
/// <param name="path">The path.</param>
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index da9dd4dfd..7985ec054 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -15,29 +17,30 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the input argument.
/// </summary>
+ /// <param name="fileSystem">The file system.</param>
/// <param name="videoPath">The video path.</param>
/// <param name="protocol">The protocol.</param>
/// <param name="isoMount">The iso mount.</param>
/// <param name="playableStreamFileNames">The playable stream file names.</param>
/// <returns>System.String[][].</returns>
- public static string[] GetInputArgument(string videoPath, MediaProtocol protocol, IIsoMount isoMount, List<string> playableStreamFileNames)
+ public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, MediaProtocol protocol, IIsoMount isoMount, List<string> playableStreamFileNames)
{
if (playableStreamFileNames.Count > 0)
{
if (isoMount == null)
{
- return GetPlayableStreamFiles(videoPath, playableStreamFileNames).ToArray();
+ return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames).ToArray();
}
- return GetPlayableStreamFiles(isoMount.MountedPath, playableStreamFileNames).ToArray();
+ return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames).ToArray();
}
return new[] {videoPath};
}
- public static List<string> GetPlayableStreamFiles(string rootPath, IEnumerable<string> filenames)
+ public static List<string> GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, IEnumerable<string> filenames)
{
- var allFiles = Directory
- .EnumerateFiles(rootPath, "*", SearchOption.AllDirectories)
+ var allFiles = fileSystem
+ .GetFilePaths(rootPath, true)
.ToList();
return filenames.Select(name => allFiles.FirstOrDefault(f => string.Equals(Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs
index 37142af19..91da5fab2 100644
--- a/MediaBrowser.Controller/Net/IHttpServer.cs
+++ b/MediaBrowser.Controller/Net/IHttpServer.cs
@@ -53,5 +53,10 @@ namespace MediaBrowser.Controller.Net
/// Inits this instance.
/// </summary>
void Init(IEnumerable<IRestfulService> services);
+
+ /// <summary>
+ /// If set, all requests will respond with this message
+ /// </summary>
+ string GlobalResponse { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs
index 6a104554a..b5efc1b8f 100644
--- a/MediaBrowser.Controller/Net/StaticResultOptions.cs
+++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs
@@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Net
public IDictionary<string, string> ResponseHeaders { get; set; }
public Action OnComplete { get; set; }
+ public Action OnError { get; set; }
public StaticResultOptions()
{
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index a4b9bf120..8fc0aedd3 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -169,6 +169,13 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="query">The query.</param>
/// <returns>List&lt;System.String&gt;.</returns>
List<string> GetPeopleNames(InternalPeopleQuery query);
+
+ /// <summary>
+ /// Gets the item ids with path.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult&lt;Tuple&lt;Guid, System.String&gt;&gt;.</returns>
+ QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query);
}
}
diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
index cbe0b97a4..a9336d8e3 100644
--- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
+++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
@@ -45,5 +45,13 @@ namespace MediaBrowser.Controller.Playlists
/// <returns>Folder.</returns>
Folder GetPlaylistsFolder(string userId);
+ /// <summary>
+ /// Moves the item.
+ /// </summary>
+ /// <param name="playlistId">The playlist identifier.</param>
+ /// <param name="entryId">The entry identifier.</param>
+ /// <param name="newIndex">The new index.</param>
+ /// <returns>Task.</returns>
+ Task MoveItem(string playlistId, string entryId, int newIndex);
}
}
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index 383d0881e..3e5353812 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -61,7 +61,16 @@ namespace MediaBrowser.Controller.Providers
};
//Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken);
- Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
+
+ try
+ {
+ Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken);
+ }
+ catch
+ {
+ Logger.Error("Error parsing xml file {0}", metadataFile);
+ throw;
+ }
}
/// <summary>
@@ -304,11 +313,7 @@ namespace MediaBrowser.Controller.Providers
{
var val = reader.ReadElementContentAsString();
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
- {
- hasLanguage.PreferredMetadataLanguage = val;
- }
+ item.PreferredMetadataLanguage = val;
break;
}
@@ -317,11 +322,7 @@ namespace MediaBrowser.Controller.Providers
{
var val = reader.ReadElementContentAsString();
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
- {
- hasLanguage.PreferredMetadataCountryCode = val;
- }
+ item.PreferredMetadataCountryCode = val;
break;
}
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 79ffb0d01..cf1c3d286 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -4,48 +4,52 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Providers
{
public class DirectoryService : IDirectoryService
{
private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
- private readonly ConcurrentDictionary<string, Dictionary<string,FileSystemInfo>> _cache =
- new ConcurrentDictionary<string, Dictionary<string, FileSystemInfo>>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>> _cache =
+ new ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>>(StringComparer.OrdinalIgnoreCase);
- public DirectoryService(ILogger logger)
+ public DirectoryService(ILogger logger, IFileSystem fileSystem)
{
_logger = logger;
+ _fileSystem = fileSystem;
}
- public DirectoryService()
- : this(new NullLogger())
+ public DirectoryService(IFileSystem fileSystem)
+ : this(new NullLogger(), fileSystem)
{
}
- public IEnumerable<FileSystemInfo> GetFileSystemEntries(string path)
+ public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path)
{
return GetFileSystemEntries(path, false);
}
- public Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path)
+ public Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path)
{
return GetFileSystemDictionary(path, false);
}
- private Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path, bool clearCache)
+ private Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path, bool clearCache)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException("path");
}
- Dictionary<string, FileSystemInfo> entries;
+ Dictionary<string, FileSystemMetadata> entries;
if (clearCache)
{
- Dictionary<string, FileSystemInfo> removed;
+ Dictionary<string, FileSystemMetadata> removed;
_cache.TryRemove(path, out removed);
}
@@ -54,13 +58,12 @@ namespace MediaBrowser.Controller.Providers
{
//_logger.Debug("Getting files for " + path);
- entries = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase);
+ entries = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
try
{
// using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
- var list = new DirectoryInfo(path).EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
- .Concat<FileSystemInfo>(new DirectoryInfo(path).EnumerateFiles("*", SearchOption.TopDirectoryOnly));
+ var list = _fileSystem.GetFileSystemEntries(path);
// Seeing dupes on some users file system for some reason
foreach (var item in list)
@@ -80,34 +83,34 @@ namespace MediaBrowser.Controller.Providers
return entries;
}
- private IEnumerable<FileSystemInfo> GetFileSystemEntries(string path, bool clearCache)
+ private IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool clearCache)
{
return GetFileSystemDictionary(path, clearCache).Values;
}
- public IEnumerable<FileSystemInfo> GetFiles(string path)
+ public IEnumerable<FileSystemMetadata> GetFiles(string path)
{
return GetFiles(path, false);
}
- public IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache)
+ public IEnumerable<FileSystemMetadata> GetFiles(string path, bool clearCache)
{
return GetFileSystemEntries(path, clearCache).Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory);
}
- public FileSystemInfo GetFile(string path)
+ public FileSystemMetadata GetFile(string path)
{
var directory = Path.GetDirectoryName(path);
var dict = GetFileSystemDictionary(directory, false);
- FileSystemInfo entry;
+ FileSystemMetadata entry;
dict.TryGetValue(path, out entry);
return entry;
}
- public IEnumerable<FileSystemInfo> GetDirectories(string path)
+ public IEnumerable<FileSystemMetadata> GetDirectories(string path)
{
return GetFileSystemEntries(path, false).Where(i => (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory);
}
diff --git a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
index 71a937cd9..fdd1891ed 100644
--- a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
+++ b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
@@ -1,12 +1,14 @@
using System;
using System.IO;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Controller.Providers
{
public class DynamicImageResponse
{
public string Path { get; set; }
+ public MediaProtocol Protocol { get; set; }
public Stream Stream { get; set; }
public ImageFormat Format { get; set; }
public bool HasImage { get; set; }
diff --git a/MediaBrowser.Controller/Providers/EpisodeIdentity.cs b/MediaBrowser.Controller/Providers/EpisodeIdentity.cs
deleted file mode 100644
index 53f469e95..000000000
--- a/MediaBrowser.Controller/Providers/EpisodeIdentity.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public class EpisodeIdentity : IItemIdentity
- {
- public string Type { get; set; }
-
- public string SeriesId { get; set; }
- public int? SeasonIndex { get; set; }
- public int IndexNumber { get; set; }
- public int? IndexNumberEnd { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
index 88a7cbab7..28abd636a 100644
--- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs
+++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
@@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers
{
- public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
+ public class EpisodeInfo : ItemLookupInfo
{
- private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
-
public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? IndexNumberEnd { get; set; }
@@ -19,16 +14,5 @@ namespace MediaBrowser.Controller.Providers
{
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
-
- public IEnumerable<EpisodeIdentity> Identities
- {
- get { return _identities; }
- }
-
- public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
- {
- var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
- _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs
index 343cf361f..062a10901 100644
--- a/MediaBrowser.Controller/Providers/IDirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs
@@ -1,15 +1,17 @@
using System.Collections.Generic;
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Providers
{
public interface IDirectoryService
{
- IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
- IEnumerable<FileSystemInfo> GetFiles(string path);
- IEnumerable<FileSystemInfo> GetDirectories(string path);
- IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
- FileSystemInfo GetFile(string path);
- Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
+ IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path);
+ IEnumerable<FileSystemMetadata> GetFiles(string path);
+ IEnumerable<FileSystemMetadata> GetDirectories(string path);
+ IEnumerable<FileSystemMetadata> GetFiles(string path, bool clearCache);
+ FileSystemMetadata GetFile(string path);
+ Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IHasIdentities.cs b/MediaBrowser.Controller/Providers/IHasIdentities.cs
deleted file mode 100644
index 36f940dd3..000000000
--- a/MediaBrowser.Controller/Providers/IHasIdentities.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- public interface IHasIdentities<out TIdentity>
- where TIdentity : IItemIdentity
- {
- IEnumerable<TIdentity> Identities { get; }
-
- Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentity.cs b/MediaBrowser.Controller/Providers/IItemIdentity.cs
deleted file mode 100644
index cab189c84..000000000
--- a/MediaBrowser.Controller/Providers/IItemIdentity.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public interface IItemIdentity
- {
- string Type { get; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs b/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
index 30e96b9e5..bfdd1dbf3 100644
--- a/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
+++ b/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
@@ -1,4 +1,4 @@
namespace MediaBrowser.Controller.Providers
{
- public interface IItemIdentityConverter : IHasOrder { }
+ public interface IItemIdentityConverter { }
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs b/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
index 9d437c208..6b403bb55 100644
--- a/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
+++ b/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
@@ -1,4 +1,4 @@
namespace MediaBrowser.Controller.Providers
{
- public interface IItemIdentityProvider : IHasOrder { }
+ public interface IItemIdentityProvider { }
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index d6fc39c5f..57e4ff320 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -195,18 +195,16 @@ namespace MediaBrowser.Controller.Providers
/// Gets the item identity providers.
/// </summary>
/// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
- /// <typeparam name="TIdentity">The type of the t identity.</typeparam>
/// <returns>IEnumerable&lt;IItemIdentityProvider&lt;TLookupInfo, TIdentity&gt;&gt;.</returns>
- IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>> GetItemIdentityProviders<TLookupInfo, TIdentity>()
- where TLookupInfo : ItemLookupInfo
- where TIdentity : IItemIdentity;
+ IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
+ where TLookupInfo : ItemLookupInfo;
/// <summary>
/// Gets the item identity converters.
/// </summary>
- /// <typeparam name="TIdentity">The type of the t identity.</typeparam>
+ /// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
/// <returns>IEnumerable&lt;IItemIdentityConverter&lt;TIdentity&gt;&gt;.</returns>
- IEnumerable<IItemIdentityConverter<TIdentity>> GetItemIdentityConverters<TIdentity>()
- where TIdentity : IItemIdentity;
+ IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
+ where TLookupInfo : ItemLookupInfo;
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ImageRefreshMode.cs b/MediaBrowser.Controller/Providers/ImageRefreshMode.cs
index df10c91f6..73ef4b8cd 100644
--- a/MediaBrowser.Controller/Providers/ImageRefreshMode.cs
+++ b/MediaBrowser.Controller/Providers/ImageRefreshMode.cs
@@ -8,14 +8,14 @@ namespace MediaBrowser.Controller.Providers
None = 0,
/// <summary>
- /// The default
+ /// Existing images will be validated
/// </summary>
- Default = 1,
+ ValidationOnly = 1,
/// <summary>
- /// Existing images will be validated
+ /// The default
/// </summary>
- ValidationOnly = 2,
+ Default = 2,
/// <summary>
/// All providers will be executed to search for new metadata
diff --git a/MediaBrowser.Controller/Providers/ItemIdentifier.cs b/MediaBrowser.Controller/Providers/ItemIdentifier.cs
index 13e4f137f..bbc6dd76c 100644
--- a/MediaBrowser.Controller/Providers/ItemIdentifier.cs
+++ b/MediaBrowser.Controller/Providers/ItemIdentifier.cs
@@ -1,73 +1,36 @@
-using System.Collections.Generic;
-using System.Linq;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers
{
- public class ItemIdentifier<TLookupInfo, TIdentity>
+ public static class ItemIdentifier<TLookupInfo>
where TLookupInfo : ItemLookupInfo
- where TIdentity : IItemIdentity
{
- public async Task<IEnumerable<TIdentity>> FindIdentities(TLookupInfo item, IProviderManager providerManager, CancellationToken cancellationToken)
+ public static async Task FindIdentities(TLookupInfo item, IProviderManager providerManager, CancellationToken cancellationToken)
{
- var providers = providerManager.GetItemIdentityProviders<TLookupInfo, TIdentity>();
- var converters = providerManager.GetItemIdentityConverters<TIdentity>();
-
- var identities = new List<IdentityPair>();
-
+ var providers = providerManager.GetItemIdentityProviders<TLookupInfo>();
+ var converters = providerManager.GetItemIdentityConverters<TLookupInfo>().ToList();
+
foreach (var provider in providers)
{
- var result = new IdentityPair
- {
- Identity = await provider.FindIdentity(item),
- Order = provider.Order
- };
-
- if (!Equals(result.Identity, default(TIdentity)))
- {
- identities.Add(result);
- }
+ await provider.Identify(item);
}
- var convertersAvailable = new List<IItemIdentityConverter<TIdentity>>(converters);
- bool changesMade;
+ bool changesMade = true;
- do
+ while (changesMade)
{
changesMade = false;
- for (int i = convertersAvailable.Count - 1; i >= 0; i--)
+ foreach (var converter in converters)
{
- var converter = convertersAvailable[i];
- var input = identities.FirstOrDefault(id => id.Identity.Type == converter.SourceType);
- var existing = identities.Where(id => id.Identity.Type == converter.ResultType);
-
- if (input != null && !existing.Any(id => id.Order <= converter.Order))
+ if (await converter.Convert(item))
{
- var result = new IdentityPair
- {
- Identity = await converter.Convert(input.Identity).ConfigureAwait(false),
- Order = converter.Order
- };
-
- if (!Equals(result.Identity, default(TIdentity)))
- {
- identities.Add(result);
- convertersAvailable.RemoveAt(i);
- changesMade = true;
- }
+ changesMade = true;
}
}
- } while (changesMade);
-
- return identities.OrderBy(id => id.Order).Select(id => id.Identity);
- }
-
- private class IdentityPair
- {
- public TIdentity Identity;
- public int Order;
+ }
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemIdentities.cs b/MediaBrowser.Controller/Providers/ItemIdentities.cs
index 939fd3b8f..48316d0f4 100644
--- a/MediaBrowser.Controller/Providers/ItemIdentities.cs
+++ b/MediaBrowser.Controller/Providers/ItemIdentities.cs
@@ -2,20 +2,15 @@
namespace MediaBrowser.Controller.Providers
{
- public interface IItemIdentityProvider<in TLookupInfo, TIdentity> : IItemIdentityProvider
+ public interface IItemIdentityProvider<in TLookupInfo> : IItemIdentityProvider
where TLookupInfo : ItemLookupInfo
- where TIdentity : IItemIdentity
{
- Task<TIdentity> FindIdentity(TLookupInfo info);
+ Task Identify(TLookupInfo info);
}
- public interface IItemIdentityConverter<TIdentity> : IItemIdentityConverter
- where TIdentity : IItemIdentity
+ public interface IItemIdentityConverter<in TLookupInfo> : IItemIdentityConverter
+ where TLookupInfo : ItemLookupInfo
{
- Task<TIdentity> Convert(TIdentity identity);
-
- string SourceType { get; }
-
- string ResultType { get; }
+ Task<bool> Convert(TLookupInfo info);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index 78f352057..d16a73028 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Providers
if (video != null)
{
VideoType = video.VideoType;
+ IsPlaceHolder = video.IsPlaceHolder;
}
}
@@ -26,5 +27,6 @@ namespace MediaBrowser.Controller.Providers
public string ContainingFolderPath { get; set; }
public VideoType VideoType { get; set; }
public bool IsInMixedFolder { get; set; }
+ public bool IsPlaceHolder { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
index 59d74def2..51916268f 100644
--- a/MediaBrowser.Controller/Providers/LocalImageInfo.cs
+++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
@@ -1,11 +1,13 @@
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Providers
{
public class LocalImageInfo
{
- public FileSystemInfo FileInfo { get; set; }
+ public FileSystemMetadata FileInfo { get; set; }
public ImageType Type { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
index dbb7fbfcd..6f217eea2 100644
--- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
+++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
@@ -1,4 +1,6 @@
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Providers
{
@@ -15,8 +17,8 @@ namespace MediaBrowser.Controller.Providers
public bool ForceSave { get; set; }
- public MetadataRefreshOptions()
- : this(new DirectoryService())
+ public MetadataRefreshOptions(IFileSystem fileSystem)
+ : this(new DirectoryService(fileSystem))
{
}
diff --git a/MediaBrowser.Controller/Providers/MetadataStatus.cs b/MediaBrowser.Controller/Providers/MetadataStatus.cs
index 283b9edbc..9b946aee2 100644
--- a/MediaBrowser.Controller/Providers/MetadataStatus.cs
+++ b/MediaBrowser.Controller/Providers/MetadataStatus.cs
@@ -41,12 +41,6 @@ namespace MediaBrowser.Controller.Providers
public DateTime? DateLastImagesRefresh { get; set; }
/// <summary>
- /// Gets or sets the last result.
- /// </summary>
- /// <value>The last result.</value>
- public ProviderRefreshStatus LastStatus { get; set; }
-
- /// <summary>
/// Gets or sets the last result error message.
/// </summary>
/// <value>The last result error message.</value>
@@ -54,33 +48,19 @@ namespace MediaBrowser.Controller.Providers
public DateTime? ItemDateModified { get; set; }
- public void AddStatus(ProviderRefreshStatus status, string errorMessage)
+ public void AddStatus(string errorMessage)
{
- if (LastStatus != status)
- {
- IsDirty = true;
- }
-
if (string.IsNullOrEmpty(LastErrorMessage))
{
LastErrorMessage = errorMessage;
}
- if (LastStatus == ProviderRefreshStatus.Success)
- {
- LastStatus = status;
- }
- }
-
- public MetadataStatus()
- {
- LastStatus = ProviderRefreshStatus.Success;
}
public bool IsDirty { get; private set; }
- public void SetDateLastMetadataRefresh(DateTime date)
+ public void SetDateLastMetadataRefresh(DateTime? date)
{
- if (date != (DateLastMetadataRefresh ?? DateTime.MinValue))
+ if (date != DateLastMetadataRefresh)
{
IsDirty = true;
}
@@ -88,9 +68,9 @@ namespace MediaBrowser.Controller.Providers
DateLastMetadataRefresh = date;
}
- public void SetDateLastImagesRefresh(DateTime date)
+ public void SetDateLastImagesRefresh(DateTime? date)
{
- if (date != (DateLastImagesRefresh ?? DateTime.MinValue))
+ if (date != DateLastImagesRefresh)
{
IsDirty = true;
}
diff --git a/MediaBrowser.Controller/Providers/SeasonIdentity.cs b/MediaBrowser.Controller/Providers/SeasonIdentity.cs
deleted file mode 100644
index 1e6b9b65a..000000000
--- a/MediaBrowser.Controller/Providers/SeasonIdentity.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public class SeasonIdentity : IItemIdentity
- {
- public string Type { get; set; }
-
- public string SeriesId { get; set; }
-
- public int SeasonIndex { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeasonInfo.cs b/MediaBrowser.Controller/Providers/SeasonInfo.cs
index 17bcd3f77..2c785d7d7 100644
--- a/MediaBrowser.Controller/Providers/SeasonInfo.cs
+++ b/MediaBrowser.Controller/Providers/SeasonInfo.cs
@@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers
{
- public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
+ public class SeasonInfo : ItemLookupInfo
{
- private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
-
public Dictionary<string, string> SeriesProviderIds { get; set; }
public int? AnimeSeriesIndex { get; set; }
@@ -17,16 +12,5 @@ namespace MediaBrowser.Controller.Providers
{
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
-
- public IEnumerable<SeasonIdentity> Identities
- {
- get { return _identities; }
- }
-
- public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
- {
- var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
- _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeriesIdentity.cs b/MediaBrowser.Controller/Providers/SeriesIdentity.cs
deleted file mode 100644
index 326d34027..000000000
--- a/MediaBrowser.Controller/Providers/SeriesIdentity.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace MediaBrowser.Controller.Providers
-{
- public class SeriesIdentity : IItemIdentity
- {
- public string Type { get; set; }
-
- public string Id { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeriesInfo.cs b/MediaBrowser.Controller/Providers/SeriesInfo.cs
index fc1119cd2..387865de2 100644
--- a/MediaBrowser.Controller/Providers/SeriesInfo.cs
+++ b/MediaBrowser.Controller/Providers/SeriesInfo.cs
@@ -1,25 +1,7 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
namespace MediaBrowser.Controller.Providers
{
- public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
+ public class SeriesInfo : ItemLookupInfo
{
- private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
-
public int? AnimeSeriesIndex { get; set; }
-
- public IEnumerable<SeriesIdentity> Identities
- {
- get { return _identities; }
- }
-
- public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
- {
- var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
- _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs
index fec6be55c..f747c055e 100644
--- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs
+++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs
@@ -3,6 +3,8 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using System.Collections.Generic;
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Controller.Resolvers
{
@@ -26,8 +28,8 @@ namespace MediaBrowser.Controller.Resolvers
public interface IMultiItemResolver
{
- MultiItemResolverResult ResolveMultiple(Folder parent,
- List<FileSystemInfo> files,
+ MultiItemResolverResult ResolveMultiple(Folder parent,
+ List<FileSystemMetadata> files,
string collectionType,
IDirectoryService directoryService);
}
@@ -35,12 +37,12 @@ namespace MediaBrowser.Controller.Resolvers
public class MultiItemResolverResult
{
public List<BaseItem> Items { get; set; }
- public List<FileSystemInfo> ExtraFiles { get; set; }
+ public List<FileSystemMetadata> ExtraFiles { get; set; }
public MultiItemResolverResult()
{
Items = new List<BaseItem>();
- ExtraFiles = new List<FileSystemInfo>();
+ ExtraFiles = new List<FileSystemMetadata>();
}
}
}
diff --git a/MediaBrowser.Controller/Themes/IAppThemeManager.cs b/MediaBrowser.Controller/Themes/IAppThemeManager.cs
deleted file mode 100644
index 1a7c2aaab..000000000
--- a/MediaBrowser.Controller/Themes/IAppThemeManager.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using MediaBrowser.Model.Themes;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Themes
-{
- public interface IAppThemeManager
- {
- /// <summary>
- /// Gets the themes.
- /// </summary>
- /// <param name="applicationName">Name of the application.</param>
- /// <returns>IEnumerable{AppThemeInfo}.</returns>
- IEnumerable<AppThemeInfo> GetThemes(string applicationName);
-
- /// <summary>
- /// Gets the theme.
- /// </summary>
- /// <param name="applicationName">Name of the application.</param>
- /// <param name="name">The name.</param>
- /// <returns>AppTheme.</returns>
- AppTheme GetTheme(string applicationName, string name);
-
- /// <summary>
- /// Saves the theme.
- /// </summary>
- /// <param name="theme">The theme.</param>
- void SaveTheme(AppTheme theme);
-
- /// <summary>
- /// Gets the image image information.
- /// </summary>
- /// <param name="applicationName">Name of the application.</param>
- /// <param name="themeName">Name of the theme.</param>
- /// <param name="imageName">Name of the image.</param>
- /// <returns>InternalThemeImage.</returns>
- InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName);
- }
-}
diff --git a/MediaBrowser.Controller/Themes/InternalThemeImage.cs b/MediaBrowser.Controller/Themes/InternalThemeImage.cs
deleted file mode 100644
index 2b676c25b..000000000
--- a/MediaBrowser.Controller/Themes/InternalThemeImage.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Themes
-{
- public class InternalThemeImage
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the cache tag.
- /// </summary>
- /// <value>The cache tag.</value>
- public string CacheTag { get; set; }
-
- /// <summary>
- /// Gets or sets the path.
- /// </summary>
- /// <value>The path.</value>
- public string Path { get; set; }
-
- /// <summary>
- /// Gets or sets the date modified.
- /// </summary>
- /// <value>The date modified.</value>
- public DateTime DateModified { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/packages.config b/MediaBrowser.Controller/packages.config
index 8846b5a06..a0aacbc95 100644
--- a/MediaBrowser.Controller/packages.config
+++ b/MediaBrowser.Controller/packages.config
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
- <package id="morelinq" version="1.1.0" targetFramework="net45" />
+ <package id="morelinq" version="1.1.1" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs b/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs
index f26ceff90..315313c04 100644
--- a/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs
+++ b/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs
@@ -18,325 +18,325 @@ using System.Threading.Tasks;
namespace MediaBrowser.Dlna.Channels
{
- public class DlnaChannelFactory : IChannelFactory, IDisposable
- {
- private readonly IServerConfigurationManager _config;
- private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
-
- private readonly IDeviceDiscovery _deviceDiscovery;
-
- private readonly SemaphoreSlim _syncLock = new SemaphoreSlim(1, 1);
- private List<Device> _servers = new List<Device>();
-
- public static DlnaChannelFactory Instance;
-
- private Func<List<string>> _localServersLookup;
-
- public DlnaChannelFactory(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger, IDeviceDiscovery deviceDiscovery)
- {
- _config = config;
- _httpClient = httpClient;
- _logger = logger;
- _deviceDiscovery = deviceDiscovery;
- Instance = this;
- }
-
- internal void Start(Func<List<string>> localServersLookup)
- {
- _localServersLookup = localServersLookup;
-
- //deviceDiscovery.DeviceDiscovered += deviceDiscovery_DeviceDiscovered;
- _deviceDiscovery.DeviceLeft += deviceDiscovery_DeviceLeft;
- }
-
- async void deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
- {
- string usn;
- if (!e.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
-
- string nt;
- if (!e.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
-
- string location;
- if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
-
- if (!IsValid(nt, usn))
- {
- return;
- }
-
- if (_localServersLookup != null)
- {
- if (_localServersLookup().Any(i => usn.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
- {
- // Don't add the local Dlna server to this
- return;
- }
- }
-
- if (GetExistingServers(usn).Any())
- {
- return;
- }
-
- await _syncLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- if (GetExistingServers(usn).Any())
- {
- return;
- }
-
- var device = await Device.CreateuPnpDeviceAsync(new Uri(location), _httpClient, _config, _logger)
- .ConfigureAwait(false);
-
- if (!_servers.Any(i => string.Equals(i.Properties.UUID, device.Properties.UUID, StringComparison.OrdinalIgnoreCase)))
- {
- _servers.Add(device);
- }
- }
- catch (Exception ex)
- {
-
- }
- finally
- {
- _syncLock.Release();
- }
- }
-
- async void deviceDiscovery_DeviceLeft(object sender, SsdpMessageEventArgs e)
- {
- string usn;
- if (!e.Headers.TryGetValue("USN", out usn)) usn = String.Empty;
-
- string nt;
- if (!e.Headers.TryGetValue("NT", out nt)) nt = String.Empty;
-
- if (!IsValid(nt, usn))
- {
- return;
- }
-
- if (!GetExistingServers(usn).Any())
- {
- return;
- }
-
- await _syncLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- var list = _servers.ToList();
-
- foreach (var device in GetExistingServers(usn).ToList())
- {
- list.Remove(device);
- }
-
- _servers = list;
- }
- finally
- {
- _syncLock.Release();
- }
- }
-
- private bool IsValid(string nt, string usn)
- {
- // It has to report that it's a media renderer
- if (usn.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
- nt.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
- usn.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1 &&
- nt.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1)
- {
- return false;
- }
-
- return true;
- }
-
- private IEnumerable<Device> GetExistingServers(string usn)
- {
- return _servers
- .Where(i => usn.IndexOf(i.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1);
- }
-
- public IEnumerable<IChannel> GetChannels()
- {
- //if (_servers.Count > 0)
- //{
- // var service = _servers[0].Properties.Services
- // .FirstOrDefault(i => string.Equals(i.ServiceType, "urn:schemas-upnp-org:service:ContentDirectory:1", StringComparison.OrdinalIgnoreCase));
-
- // var controlUrl = service == null ? null : (_servers[0].Properties.BaseUrl.TrimEnd('/') + "/" + service.ControlUrl.TrimStart('/'));
-
- // if (!string.IsNullOrEmpty(controlUrl))
- // {
- // return new List<IChannel>
- // {
- // new ServerChannel(_servers.ToList(), _httpClient, _logger, controlUrl)
- // };
- // }
- //}
-
- return new List<IChannel>();
- }
-
- public void Dispose()
- {
- if (_deviceDiscovery != null)
- {
- _deviceDiscovery.DeviceDiscovered -= deviceDiscovery_DeviceDiscovered;
- _deviceDiscovery.DeviceLeft -= deviceDiscovery_DeviceLeft;
- }
- }
- }
-
- public class ServerChannel : IChannel, IFactoryChannel
- {
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
- public string ControlUrl { get; set; }
- public List<Device> Servers { get; set; }
-
- public ServerChannel(IHttpClient httpClient, ILogger logger)
- {
- _httpClient = httpClient;
- _logger = logger;
- Servers = new List<Device>();
- }
-
- public string Name
- {
- get { return "Devices"; }
- }
-
- public string Description
- {
- get { return string.Empty; }
- }
-
- public string DataVersion
- {
- get { return DateTime.UtcNow.Ticks.ToString(); }
- }
-
- public string HomePageUrl
- {
- get { return string.Empty; }
- }
-
- public ChannelParentalRating ParentalRating
- {
- get { return ChannelParentalRating.GeneralAudience; }
- }
-
- public InternalChannelFeatures GetChannelFeatures()
- {
- return new InternalChannelFeatures
- {
- ContentTypes = new List<ChannelMediaContentType>
- {
- ChannelMediaContentType.Song,
- ChannelMediaContentType.Clip
- },
-
- MediaTypes = new List<ChannelMediaType>
- {
- ChannelMediaType.Audio,
- ChannelMediaType.Video,
- ChannelMediaType.Photo
- }
- };
- }
-
- public bool IsEnabledFor(string userId)
- {
- return true;
- }
-
- public async Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken)
- {
- IEnumerable<ChannelItemInfo> items;
-
- if (string.IsNullOrWhiteSpace(query.FolderId))
- {
- items = Servers.Select(i => new ChannelItemInfo
- {
- FolderType = ChannelFolderType.Container,
- Id = GetServerId(i),
- Name = i.Properties.Name,
- Overview = i.Properties.ModelDescription,
- Type = ChannelItemType.Folder
- });
- }
- else
- {
- var idParts = query.FolderId.Split('|');
- var folderId = idParts.Length == 2 ? idParts[1] : null;
-
- var result = await new ContentDirectoryBrowser(_httpClient, _logger).Browse(new ContentDirectoryBrowseRequest
- {
- Limit = query.Limit,
- StartIndex = query.StartIndex,
- ParentId = folderId,
- ContentDirectoryUrl = ControlUrl
-
- }, cancellationToken).ConfigureAwait(false);
-
- items = result.Items.ToList();
- }
-
- var list = items.ToList();
- var count = list.Count;
-
- list = ApplyPaging(list, query).ToList();
-
- return new ChannelItemResult
- {
- Items = list,
- TotalRecordCount = count
- };
- }
-
- private string GetServerId(Device device)
- {
- return device.Properties.UUID.GetMD5().ToString("N");
- }
-
- private IEnumerable<T> ApplyPaging<T>(IEnumerable<T> items, InternalChannelItemQuery query)
- {
- if (query.StartIndex.HasValue)
- {
- items = items.Skip(query.StartIndex.Value);
- }
-
- if (query.Limit.HasValue)
- {
- items = items.Take(query.Limit.Value);
- }
-
- return items;
- }
-
- public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken)
- {
- // TODO: Implement
- return Task.FromResult(new DynamicImageResponse
- {
- HasImage = false
- });
- }
-
- public IEnumerable<ImageType> GetSupportedChannelImages()
- {
- return new List<ImageType>
- {
- ImageType.Primary
- };
- }
- }
+ //public class DlnaChannelFactory : IChannelFactory, IDisposable
+ //{
+ // private readonly IServerConfigurationManager _config;
+ // private readonly ILogger _logger;
+ // private readonly IHttpClient _httpClient;
+
+ // private readonly IDeviceDiscovery _deviceDiscovery;
+
+ // private readonly SemaphoreSlim _syncLock = new SemaphoreSlim(1, 1);
+ // private List<Device> _servers = new List<Device>();
+
+ // public static DlnaChannelFactory Instance;
+
+ // private Func<List<string>> _localServersLookup;
+
+ // public DlnaChannelFactory(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger, IDeviceDiscovery deviceDiscovery)
+ // {
+ // _config = config;
+ // _httpClient = httpClient;
+ // _logger = logger;
+ // _deviceDiscovery = deviceDiscovery;
+ // Instance = this;
+ // }
+
+ // internal void Start(Func<List<string>> localServersLookup)
+ // {
+ // _localServersLookup = localServersLookup;
+
+ // //deviceDiscovery.DeviceDiscovered += deviceDiscovery_DeviceDiscovered;
+ // _deviceDiscovery.DeviceLeft += deviceDiscovery_DeviceLeft;
+ // }
+
+ // async void deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
+ // {
+ // string usn;
+ // if (!e.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
+
+ // string nt;
+ // if (!e.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
+
+ // string location;
+ // if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
+
+ // if (!IsValid(nt, usn))
+ // {
+ // return;
+ // }
+
+ // if (_localServersLookup != null)
+ // {
+ // if (_localServersLookup().Any(i => usn.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
+ // {
+ // // Don't add the local Dlna server to this
+ // return;
+ // }
+ // }
+
+ // if (GetExistingServers(usn).Any())
+ // {
+ // return;
+ // }
+
+ // await _syncLock.WaitAsync().ConfigureAwait(false);
+
+ // try
+ // {
+ // if (GetExistingServers(usn).Any())
+ // {
+ // return;
+ // }
+
+ // var device = await Device.CreateuPnpDeviceAsync(new Uri(location), _httpClient, _config, _logger)
+ // .ConfigureAwait(false);
+
+ // if (!_servers.Any(i => string.Equals(i.Properties.UUID, device.Properties.UUID, StringComparison.OrdinalIgnoreCase)))
+ // {
+ // _servers.Add(device);
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+
+ // }
+ // finally
+ // {
+ // _syncLock.Release();
+ // }
+ // }
+
+ // async void deviceDiscovery_DeviceLeft(object sender, SsdpMessageEventArgs e)
+ // {
+ // string usn;
+ // if (!e.Headers.TryGetValue("USN", out usn)) usn = String.Empty;
+
+ // string nt;
+ // if (!e.Headers.TryGetValue("NT", out nt)) nt = String.Empty;
+
+ // if (!IsValid(nt, usn))
+ // {
+ // return;
+ // }
+
+ // if (!GetExistingServers(usn).Any())
+ // {
+ // return;
+ // }
+
+ // await _syncLock.WaitAsync().ConfigureAwait(false);
+
+ // try
+ // {
+ // var list = _servers.ToList();
+
+ // foreach (var device in GetExistingServers(usn).ToList())
+ // {
+ // list.Remove(device);
+ // }
+
+ // _servers = list;
+ // }
+ // finally
+ // {
+ // _syncLock.Release();
+ // }
+ // }
+
+ // private bool IsValid(string nt, string usn)
+ // {
+ // // It has to report that it's a media renderer
+ // if (usn.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ // nt.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ // usn.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1 &&
+ // nt.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1)
+ // {
+ // return false;
+ // }
+
+ // return true;
+ // }
+
+ // private IEnumerable<Device> GetExistingServers(string usn)
+ // {
+ // return _servers
+ // .Where(i => usn.IndexOf(i.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1);
+ // }
+
+ // public IEnumerable<IChannel> GetChannels()
+ // {
+ // //if (_servers.Count > 0)
+ // //{
+ // // var service = _servers[0].Properties.Services
+ // // .FirstOrDefault(i => string.Equals(i.ServiceType, "urn:schemas-upnp-org:service:ContentDirectory:1", StringComparison.OrdinalIgnoreCase));
+
+ // // var controlUrl = service == null ? null : (_servers[0].Properties.BaseUrl.TrimEnd('/') + "/" + service.ControlUrl.TrimStart('/'));
+
+ // // if (!string.IsNullOrEmpty(controlUrl))
+ // // {
+ // // return new List<IChannel>
+ // // {
+ // // new ServerChannel(_servers.ToList(), _httpClient, _logger, controlUrl)
+ // // };
+ // // }
+ // //}
+
+ // return new List<IChannel>();
+ // }
+
+ // public void Dispose()
+ // {
+ // if (_deviceDiscovery != null)
+ // {
+ // _deviceDiscovery.DeviceDiscovered -= deviceDiscovery_DeviceDiscovered;
+ // _deviceDiscovery.DeviceLeft -= deviceDiscovery_DeviceLeft;
+ // }
+ // }
+ //}
+
+ //public class ServerChannel : IChannel, IFactoryChannel
+ //{
+ // private readonly IHttpClient _httpClient;
+ // private readonly ILogger _logger;
+ // public string ControlUrl { get; set; }
+ // public List<Device> Servers { get; set; }
+
+ // public ServerChannel(IHttpClient httpClient, ILogger logger)
+ // {
+ // _httpClient = httpClient;
+ // _logger = logger;
+ // Servers = new List<Device>();
+ // }
+
+ // public string Name
+ // {
+ // get { return "Devices"; }
+ // }
+
+ // public string Description
+ // {
+ // get { return string.Empty; }
+ // }
+
+ // public string DataVersion
+ // {
+ // get { return DateTime.UtcNow.Ticks.ToString(); }
+ // }
+
+ // public string HomePageUrl
+ // {
+ // get { return string.Empty; }
+ // }
+
+ // public ChannelParentalRating ParentalRating
+ // {
+ // get { return ChannelParentalRating.GeneralAudience; }
+ // }
+
+ // public InternalChannelFeatures GetChannelFeatures()
+ // {
+ // return new InternalChannelFeatures
+ // {
+ // ContentTypes = new List<ChannelMediaContentType>
+ // {
+ // ChannelMediaContentType.Song,
+ // ChannelMediaContentType.Clip
+ // },
+
+ // MediaTypes = new List<ChannelMediaType>
+ // {
+ // ChannelMediaType.Audio,
+ // ChannelMediaType.Video,
+ // ChannelMediaType.Photo
+ // }
+ // };
+ // }
+
+ // public bool IsEnabledFor(string userId)
+ // {
+ // return true;
+ // }
+
+ // public async Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken)
+ // {
+ // IEnumerable<ChannelItemInfo> items;
+
+ // if (string.IsNullOrWhiteSpace(query.FolderId))
+ // {
+ // items = Servers.Select(i => new ChannelItemInfo
+ // {
+ // FolderType = ChannelFolderType.Container,
+ // Id = GetServerId(i),
+ // Name = i.Properties.Name,
+ // Overview = i.Properties.ModelDescription,
+ // Type = ChannelItemType.Folder
+ // });
+ // }
+ // else
+ // {
+ // var idParts = query.FolderId.Split('|');
+ // var folderId = idParts.Length == 2 ? idParts[1] : null;
+
+ // var result = await new ContentDirectoryBrowser(_httpClient, _logger).Browse(new ContentDirectoryBrowseRequest
+ // {
+ // Limit = query.Limit,
+ // StartIndex = query.StartIndex,
+ // ParentId = folderId,
+ // ContentDirectoryUrl = ControlUrl
+
+ // }, cancellationToken).ConfigureAwait(false);
+
+ // items = result.Items.ToList();
+ // }
+
+ // var list = items.ToList();
+ // var count = list.Count;
+
+ // list = ApplyPaging(list, query).ToList();
+
+ // return new ChannelItemResult
+ // {
+ // Items = list,
+ // TotalRecordCount = count
+ // };
+ // }
+
+ // private string GetServerId(Device device)
+ // {
+ // return device.Properties.UUID.GetMD5().ToString("N");
+ // }
+
+ // private IEnumerable<T> ApplyPaging<T>(IEnumerable<T> items, InternalChannelItemQuery query)
+ // {
+ // if (query.StartIndex.HasValue)
+ // {
+ // items = items.Skip(query.StartIndex.Value);
+ // }
+
+ // if (query.Limit.HasValue)
+ // {
+ // items = items.Take(query.Limit.Value);
+ // }
+
+ // return items;
+ // }
+
+ // public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken)
+ // {
+ // // TODO: Implement
+ // return Task.FromResult(new DynamicImageResponse
+ // {
+ // HasImage = false
+ // });
+ // }
+
+ // public IEnumerable<ImageType> GetSupportedChannelImages()
+ // {
+ // return new List<ImageType>
+ // {
+ // ImageType.Primary
+ // };
+ // }
+ //}
}
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 72040c8ae..a9ce5587d 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -523,7 +523,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
if (context == null || context.IsFolder)
{
var movie = item as Movie;
- if (movie != null && options.EnableEnhancedMovies)
+ if (movie != null && options.EnableMovieFolders)
{
if (movie.GetTrailerIds().Count > 0 ||
movie.SpecialFeatureIds.Count > 0)
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 390f44267..5589a6e3b 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -163,7 +163,8 @@ namespace MediaBrowser.Dlna.Didl
streamInfo.IsTargetCabac,
streamInfo.TargetRefFrames,
streamInfo.TargetVideoStreamCount,
- streamInfo.TargetAudioStreamCount);
+ streamInfo.TargetAudioStreamCount,
+ streamInfo.TargetVideoCodecTag);
foreach (var contentFeature in contentFeatureList)
{
@@ -301,7 +302,8 @@ namespace MediaBrowser.Dlna.Didl
streamInfo.IsTargetCabac,
streamInfo.TargetRefFrames,
streamInfo.TargetVideoStreamCount,
- streamInfo.TargetAudioStreamCount);
+ streamInfo.TargetAudioStreamCount,
+ streamInfo.TargetVideoCodecTag);
var filename = url.Substring(0, url.IndexOf('?'));
@@ -996,6 +998,10 @@ namespace MediaBrowser.Dlna.Didl
//}
+ var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
+ .TrimStart('.')
+ .Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
+
return new ImageDownloadInfo
{
ItemId = item.Id.ToString("N"),
@@ -1003,7 +1009,7 @@ namespace MediaBrowser.Dlna.Didl
ImageTag = tag,
Width = width,
Height = height,
- File = imageInfo.Path,
+ Format = inputFormat,
ItemImageInfo = imageInfo
};
}
@@ -1019,7 +1025,7 @@ namespace MediaBrowser.Dlna.Didl
internal bool IsDirectStream;
- internal string File;
+ internal string Format;
internal ItemImageInfo ItemImageInfo;
}
@@ -1082,14 +1088,10 @@ namespace MediaBrowser.Dlna.Didl
width = Convert.ToInt32(newSize.Width);
height = Convert.ToInt32(newSize.Height);
- var inputFormat = (Path.GetExtension(info.File) ?? string.Empty)
- .TrimStart('.')
- .Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
-
var normalizedFormat = format
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
- if (string.Equals(inputFormat, normalizedFormat, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(info.Format, normalizedFormat, StringComparison.OrdinalIgnoreCase))
{
info.IsDirectStream = maxWidth >= width.Value && maxHeight >= height.Value;
}
diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs
index 95e2aaa77..be49c0f89 100644
--- a/MediaBrowser.Dlna/DlnaManager.cs
+++ b/MediaBrowser.Dlna/DlnaManager.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
+using CommonIO;
namespace MediaBrowser.Dlna
{
@@ -279,8 +280,7 @@ namespace MediaBrowser.Dlna
{
try
{
- return new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ return _fileSystem.GetFiles(path)
.Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
.Select(i => ParseProfileXmlFile(i.FullName, type))
.Where(i => i != null)
@@ -342,8 +342,7 @@ namespace MediaBrowser.Dlna
{
try
{
- return new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ return _fileSystem.GetFiles(path)
.Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
.Select(i => new InternalProfileInfo
{
@@ -385,7 +384,7 @@ namespace MediaBrowser.Dlna
if (!fileInfo.Exists || fileInfo.Length != stream.Length)
{
- Directory.CreateDirectory(systemProfilesPath);
+ _fileSystem.CreateDirectory(systemProfilesPath);
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{
@@ -396,7 +395,7 @@ namespace MediaBrowser.Dlna
}
// Not necessary, but just to make it easy to find
- Directory.CreateDirectory(UserProfilesPath);
+ _fileSystem.CreateDirectory(UserProfilesPath);
}
public void DeleteProfile(string id)
diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
index bdb778cab..8c45757e7 100644
--- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
+++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
@@ -81,8 +81,6 @@ namespace MediaBrowser.Dlna.Main
ReloadComponents();
_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
-
- DlnaChannelFactory.Instance.Start(() => _registeredServerIds);
}
void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index c49cbc654..b8ac60ef6 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
@@ -13,6 +13,7 @@
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -39,6 +40,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -230,6 +238,9 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index 941b2aeca..cb3629678 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -525,7 +525,8 @@ namespace MediaBrowser.Dlna.PlayTo
streamInfo.IsTargetCabac,
streamInfo.TargetRefFrames,
streamInfo.TargetVideoStreamCount,
- streamInfo.TargetAudioStreamCount);
+ streamInfo.TargetAudioStreamCount,
+ streamInfo.TargetVideoCodecTag);
return list.FirstOrDefault();
}
diff --git a/MediaBrowser.Dlna/Ssdp/Datagram.cs b/MediaBrowser.Dlna/Ssdp/Datagram.cs
index 0a6d27303..590194534 100644
--- a/MediaBrowser.Dlna/Ssdp/Datagram.cs
+++ b/MediaBrowser.Dlna/Ssdp/Datagram.cs
@@ -11,17 +11,17 @@ namespace MediaBrowser.Dlna.Ssdp
public EndPoint ToEndPoint { get; private set; }
public EndPoint FromEndPoint { get; private set; }
public string Message { get; private set; }
- public bool IgnoreBindFailure { get; private set; }
+ public bool IsBroadcast { get; private set; }
public bool EnableDebugLogging { get; private set; }
private readonly ILogger _logger;
- public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure, bool enableDebugLogging)
+ public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool isBroadcast, bool enableDebugLogging)
{
Message = message;
_logger = logger;
EnableDebugLogging = enableDebugLogging;
- IgnoreBindFailure = ignoreBindFailure;
+ IsBroadcast = isBroadcast;
FromEndPoint = fromEndPoint;
ToEndPoint = toEndPoint;
}
@@ -30,7 +30,7 @@ namespace MediaBrowser.Dlna.Ssdp
{
var msg = Encoding.ASCII.GetBytes(Message);
- var socket = CreateSocket(!IgnoreBindFailure);
+ var socket = CreateSocket();
if (socket == null)
{
@@ -50,10 +50,9 @@ namespace MediaBrowser.Dlna.Ssdp
_logger.ErrorException("Error binding datagram socket", ex);
}
- if (!IgnoreBindFailure)
+ if (IsBroadcast)
{
CloseSocket(socket, false);
-
return;
}
}
@@ -69,7 +68,7 @@ namespace MediaBrowser.Dlna.Ssdp
}
catch (Exception ex)
{
- if (!IgnoreBindFailure || EnableDebugLogging)
+ if (EnableDebugLogging)
{
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
}
@@ -102,18 +101,17 @@ namespace MediaBrowser.Dlna.Ssdp
}
}
- private Socket CreateSocket(bool isBroadcast)
+ private Socket CreateSocket()
{
try
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
- if (isBroadcast)
+ if (IsBroadcast)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
- socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
}
return socket;
diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
index e6e9624d5..5dd05fd64 100644
--- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
@@ -139,14 +139,14 @@ namespace MediaBrowser.Dlna.Ssdp
values["MX"] = "3";
// UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
- SendDatagram("M-SEARCH * HTTP/1.1", values, _ssdpEndp, localIp, false, 2);
+ SendDatagram("M-SEARCH * HTTP/1.1", values, _ssdpEndp, localIp, true, 2);
}
public void SendDatagram(string header,
Dictionary<string, string> values,
EndPoint endpoint,
EndPoint localAddress,
- bool ignoreBindFailure,
+ bool isBroadcast,
int sendCount)
{
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
@@ -156,7 +156,7 @@ namespace MediaBrowser.Dlna.Ssdp
for (var i = 0; i < sendCount; i++)
{
- var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure, enableDebugLogging);
+ var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging);
if (_messageQueue.Count == 0)
{
@@ -230,8 +230,8 @@ namespace MediaBrowser.Dlna.Ssdp
values["ST"] = d.Type;
values["USN"] = d.USN;
- SendDatagram(header, values, endpoint, null, true, 1);
- SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
+ SendDatagram(header, values, endpoint, null, false, 1);
+ SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), false, 1);
//SendDatagram(header, values, endpoint, null, true);
if (enableDebugLogging)
@@ -516,7 +516,7 @@ namespace MediaBrowser.Dlna.Ssdp
_logger.Debug("{0} said {1}", dev.USN, type);
}
- SendDatagram(header, values, _ssdpEndp, new IPEndPoint(dev.Address, 0), false, sendCount);
+ SendDatagram(header, values, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, sendCount);
}
public void RegisterNotification(Guid uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
diff --git a/MediaBrowser.Dlna/packages.config b/MediaBrowser.Dlna/packages.config
new file mode 100644
index 000000000..fad6af08e
--- /dev/null
+++ b/MediaBrowser.Dlna/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
index aa0f11475..0364eaf99 100644
--- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs
@@ -5,6 +5,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.LocalMetadata
{
@@ -54,7 +55,7 @@ namespace MediaBrowser.LocalMetadata
FileSystem = fileSystem;
}
- protected abstract FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService);
+ protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
diff --git a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
index 90f00ff02..de2f55161 100644
--- a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Images
{
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index 0089a71d5..7e64c9f5d 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Images
{
@@ -60,7 +61,7 @@ namespace MediaBrowser.LocalMetadata.Images
return new List<LocalImageInfo>();
}
- private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, IEnumerable<FileSystemInfo> parentPathFiles)
+ private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, IEnumerable<FileSystemMetadata> parentPathFiles)
{
var thumbName = filenameWithoutExtension + "-thumb";
@@ -91,7 +92,7 @@ namespace MediaBrowser.LocalMetadata.Images
})
.Select(i => new LocalImageInfo
{
- FileInfo = (FileInfo)i,
+ FileInfo = i,
Type = ImageType.Primary
})
.ToList();
diff --git a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
index 52cff0aa9..dc6f2ae93 100644
--- a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
index f118c2763..664603315 100644
--- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using System.Collections.Generic;
using System.IO;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Images
{
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index ba87b3c43..3c9736429 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Images
{
@@ -62,11 +63,11 @@ namespace MediaBrowser.LocalMetadata.Images
return false;
}
- private IEnumerable<FileSystemInfo> GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService)
+ private IEnumerable<FileSystemMetadata> GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService)
{
if (item.LocationType != LocationType.FileSystem)
{
- return new List<FileSystemInfo>();
+ return new List<FileSystemMetadata>();
}
var path = item.ContainingFolderPath;
@@ -127,7 +128,7 @@ namespace MediaBrowser.LocalMetadata.Images
return list;
}
- private void PopulateImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
+ private void PopulateImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
{
var imagePrefix = item.FileNameWithoutExtension + "-";
var isInMixedFolder = item.IsInMixedFolder;
@@ -164,7 +165,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- private void PopulatePrimaryImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder)
+ private void PopulatePrimaryImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
{
var names = new List<string>
{
@@ -206,7 +207,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- private void PopulateBackdrops(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
+ private void PopulateBackdrops(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
{
PopulateBackdrops(images, files, imagePrefix, "backdrop", "backdrop", isInMixedFolder, ImageType.Backdrop);
@@ -261,12 +262,12 @@ namespace MediaBrowser.LocalMetadata.Images
}));
}
- private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder)
+ private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
{
PopulateBackdrops(images, files, imagePrefix, "screenshot", "screenshot", isInMixedFolder, ImageType.Screenshot);
}
- private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
+ private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
{
AddImage(files, images, imagePrefix + firstFileName, type);
@@ -349,7 +350,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- private bool AddImage(List<FileSystemInfo> files, List<LocalImageInfo> images, string name, string imagePrefix, bool isInMixedFolder, ImageType type)
+ private bool AddImage(List<FileSystemMetadata> files, List<LocalImageInfo> images, string name, string imagePrefix, bool isInMixedFolder, ImageType type)
{
var added = AddImage(files, images, imagePrefix + name, type);
@@ -364,9 +365,9 @@ namespace MediaBrowser.LocalMetadata.Images
return added;
}
- private bool AddImage(IEnumerable<FileSystemInfo> files, List<LocalImageInfo> images, string name, ImageType type)
+ private bool AddImage(IEnumerable<FileSystemMetadata> files, List<LocalImageInfo> images, string name, ImageType type)
{
- var image = GetImage(files, name) as FileInfo;
+ var image = GetImage(files, name);
if (image != null)
{
@@ -382,7 +383,7 @@ namespace MediaBrowser.LocalMetadata.Images
return false;
}
- private void AddCacheKeyImage(IEnumerable<FileSystemInfo> files, List<LocalImageInfo> images, ImageType type)
+ private void AddCacheKeyImage(IEnumerable<FileSystemMetadata> files, List<LocalImageInfo> images, ImageType type)
{
var candidates = files
.Where(i => _fileSystem.GetFileNameWithoutExtension(i).StartsWith(type.ToString() + "_key_", StringComparison.OrdinalIgnoreCase))
@@ -390,7 +391,7 @@ namespace MediaBrowser.LocalMetadata.Images
var image = BaseItem.SupportedImageExtensions
.Select(i => candidates.FirstOrDefault(c => string.Equals(c.Extension, i, StringComparison.OrdinalIgnoreCase)))
- .FirstOrDefault(i => i != null) as FileInfo;
+ .FirstOrDefault(i => i != null);
if (image != null)
{
@@ -402,7 +403,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name)
+ private FileSystemMetadata GetImage(IEnumerable<FileSystemMetadata> files, string name)
{
return files.FirstOrDefault(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase));
}
diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
index 14cec3627..a74fe7e98 100644
--- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
+++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
@@ -11,6 +11,7 @@
<AssemblyName>MediaBrowser.LocalMetadata</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -30,6 +31,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -95,7 +103,9 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs
index 08454c8e7..e3cc64605 100644
--- a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs
@@ -8,6 +8,8 @@ using System.Globalization;
using System.IO;
using System.Threading;
using System.Xml;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Parsers
{
@@ -17,10 +19,12 @@ namespace MediaBrowser.LocalMetadata.Parsers
public class EpisodeXmlParser : BaseItemXmlParser<Episode>
{
private List<LocalImageInfo> _imagesFound;
+ private readonly IFileSystem _fileSystem;
- public EpisodeXmlParser(ILogger logger)
+ public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem)
: base(logger)
{
+ _fileSystem = fileSystem;
}
private string _xmlPath;
@@ -80,7 +84,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
var parentFolder = Path.GetDirectoryName(_xmlPath);
filename = Path.Combine(parentFolder, filename);
- var file = new FileInfo(filename);
+ var file = _fileSystem.GetFileInfo(filename);
if (file.Exists)
{
diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
index fc22e75c5..01eaf33d2 100644
--- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -26,7 +27,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new BoxSetXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "collection.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs
index bf2730032..17ef5fd2e 100644
--- a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Logging;
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -25,12 +26,12 @@ namespace MediaBrowser.LocalMetadata.Providers
var images = new List<LocalImageInfo>();
var chapters = new List<ChapterInfo>();
- new EpisodeXmlParser(_logger).Fetch(result, images, path, cancellationToken);
+ new EpisodeXmlParser(_logger, FileSystem).Fetch(result, images, path, cancellationToken);
result.Images = images;
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
var metadataPath = Path.GetDirectoryName(info.Path);
metadataPath = Path.Combine(metadataPath, "metadata");
diff --git a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs
index bf059c553..20fa889cc 100644
--- a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -25,9 +26,9 @@ namespace MediaBrowser.LocalMetadata.Providers
new BaseItemXmlParser<Folder>(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
- return new FileInfo(Path.Combine(info.Path, "folder.xml"));
+ return directoryService.GetFile(Path.Combine(info.Path, "folder.xml"));
}
}
}
diff --git a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
index f51605f06..6abb019b4 100644
--- a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -23,7 +24,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new GameSystemXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "gamesystem.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
index 7ee2c768b..8d1a4d690 100644
--- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -23,12 +24,12 @@ namespace MediaBrowser.LocalMetadata.Providers
new GameXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
var specificFile = Path.ChangeExtension(info.Path, ".xml");
- var file = new FileInfo(specificFile);
+ var file = FileSystem.GetFileInfo(specificFile);
- return info.IsInMixedFolder || file.Exists ? file : new FileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml"));
+ return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml"));
}
}
}
diff --git a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs
index 82c7dbd67..0930e9198 100644
--- a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -23,27 +24,22 @@ namespace MediaBrowser.LocalMetadata.Providers
new MovieXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return GetXmlFileInfo(info, FileSystem);
}
- public static FileInfo GetXmlFileInfo(ItemInfo info, IFileSystem fileSystem)
+ public static FileSystemMetadata GetXmlFileInfo(ItemInfo info, IFileSystem fileSystem)
{
var fileInfo = fileSystem.GetFileSystemInfo(info.Path);
- var directoryInfo = fileInfo as DirectoryInfo;
-
- if (directoryInfo == null)
- {
- directoryInfo = new DirectoryInfo(Path.GetDirectoryName(info.Path));
- }
+ var directoryInfo = fileInfo.IsDirectory ? fileInfo : fileSystem.GetDirectoryInfo(Path.GetDirectoryName(info.Path));
var directoryPath = directoryInfo.FullName;
var specificFile = Path.Combine(directoryPath, fileSystem.GetFileNameWithoutExtension(info.Path) + ".xml");
- var file = new FileInfo(specificFile);
+ var file = fileSystem.GetFileInfo(specificFile);
// In a mixed folder, only {moviename}.xml is supported
if (info.IsInMixedFolder)
@@ -52,7 +48,7 @@ namespace MediaBrowser.LocalMetadata.Providers
}
// If in it's own folder, prefer movie.xml, but allow the specific file as well
- var movieFile = new FileInfo(Path.Combine(directoryPath, "movie.xml"));
+ var movieFile = fileSystem.GetFileInfo(Path.Combine(directoryPath, "movie.xml"));
return movieFile.Exists ? movieFile : file;
}
diff --git a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs
index 3171dd9a7..e24e46310 100644
--- a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -23,7 +24,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new MusicVideoXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return MovieXmlProvider.GetXmlFileInfo(info, FileSystem);
}
diff --git a/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs
index 115d5b041..dd3541d56 100644
--- a/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -22,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new BaseItemXmlParser<Person>(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "person.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
index 3de311e2b..81c87ee4d 100644
--- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -23,7 +24,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new PlaylistXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "playlist.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs
index f0c8f0fa1..bea0de88e 100644
--- a/MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -26,7 +27,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new SeasonXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "season.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
index 80fdad483..85bbcbc02 100644
--- a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Threading;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
@@ -26,7 +27,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new SeriesXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "series.xml"));
}
diff --git a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs
index 56d289f97..0600161b3 100644
--- a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs
+++ b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs
@@ -5,6 +5,7 @@ using MediaBrowser.LocalMetadata.Parsers;
using MediaBrowser.Model.Logging;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.LocalMetadata.Providers
{
@@ -23,7 +24,7 @@ namespace MediaBrowser.LocalMetadata.Providers
new VideoXmlParser(_logger).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return MovieXmlProvider.GetXmlFileInfo(info, FileSystem);
}
diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs
index e6ae84169..b709c9b83 100644
--- a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -21,11 +23,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public BoxSetXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public BoxSetXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -62,7 +66,7 @@ namespace MediaBrowser.LocalMetadata.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config);
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs
index 96d95d40b..dc8a16cd8 100644
--- a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs
@@ -9,6 +9,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -19,12 +21,14 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private IFileSystem _fileSystem;
- public EpisodeXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager)
+ public EpisodeXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_itemRepository = itemRepository;
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -143,7 +147,8 @@ namespace MediaBrowser.LocalMetadata.Savers
"DVD_episodenumber",
"DVD_season",
"absolute_number"
- }, _config);
+
+ }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
index ac56f0864..73a90ac85 100644
--- a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
@@ -9,6 +9,8 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -24,11 +26,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public FolderXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public FolderXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -76,7 +80,7 @@ namespace MediaBrowser.LocalMetadata.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config);
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
index 770f1d7f9..57a8900a4 100644
--- a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
@@ -6,6 +6,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -21,11 +23,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public GameSystemXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public GameSystemXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -69,7 +73,7 @@ namespace MediaBrowser.LocalMetadata.Savers
var xmlFilePath = GetSavePath(item);
- XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config);
+ XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> { }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
index 26c4ff395..89c274e12 100644
--- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
@@ -8,6 +8,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -26,11 +28,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public GameXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public GameXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -101,7 +105,7 @@ namespace MediaBrowser.LocalMetadata.Savers
"GameSystem",
"NesBox",
"NesBoxRom"
- }, _config);
+ }, _config, _fileSystem);
}
public string GetSavePath(IHasMetadata item)
diff --git a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
index a6fba3e9b..2e3e7aaa1 100644
--- a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
@@ -9,6 +9,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -20,12 +22,14 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IItemRepository _itemRepository;
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private IFileSystem _fileSystem;
- public MovieXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager)
+ public MovieXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_itemRepository = itemRepository;
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
public string Name
@@ -122,7 +126,7 @@ namespace MediaBrowser.LocalMetadata.Savers
"Artist",
"Album",
"TmdbCollectionName"
- }, _config);
+ }, _config, _fileSystem);
}
public string GetSavePath(IHasMetadata item)
diff --git a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
index 9d943bfa4..481c5967d 100644
--- a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
@@ -6,6 +6,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -24,11 +26,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public PersonXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public PersonXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -75,7 +79,7 @@ namespace MediaBrowser.LocalMetadata.Savers
XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
{
"PlaceOfBirth"
- }, _config);
+ }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
index 7dfe59b4b..d03b45dcd 100644
--- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
@@ -7,6 +7,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -22,11 +24,13 @@ namespace MediaBrowser.LocalMetadata.Savers
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public PlaylistXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public PlaylistXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -75,7 +79,7 @@ namespace MediaBrowser.LocalMetadata.Savers
"OwnerUserId",
"PlaylistMediaType"
- }, _config);
+ }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs
index 44b1cd8d3..9806c4216 100644
--- a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs
@@ -9,6 +9,8 @@ using System.IO;
using System.Security;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -16,11 +18,13 @@ namespace MediaBrowser.LocalMetadata.Savers
{
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private IFileSystem _fileSystem;
- public SeriesXmlProvider(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public SeriesXmlProvider(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
public string Name
@@ -134,7 +138,7 @@ namespace MediaBrowser.LocalMetadata.Savers
// Deprecated. No longer saving in this field.
"AnimeSeriesIndex"
- }, _config);
+ }, _config, _fileSystem);
}
/// <summary>
diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
index 091d59469..c9a4cb537 100644
--- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
@@ -14,6 +14,8 @@ using System.Linq;
using System.Security;
using System.Text;
using System.Xml;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.LocalMetadata.Savers
{
@@ -130,9 +132,9 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="xml">The XML.</param>
/// <param name="path">The path.</param>
/// <param name="xmlTagsUsed">The XML tags used.</param>
- public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config)
+ public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config, IFileSystem fileSystem)
{
- if (File.Exists(path))
+ if (fileSystem.FileExists(path))
{
var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase);
xml.Insert(position, GetCustomTags(path, xmlTagsUsed));
@@ -144,7 +146,7 @@ namespace MediaBrowser.LocalMetadata.Savers
//Add the new node to the document.
xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var wasHidden = false;
@@ -425,17 +427,13 @@ namespace MediaBrowser.LocalMetadata.Savers
}
}
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
+ if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage))
{
- if (!string.IsNullOrEmpty(hasLanguage.PreferredMetadataLanguage))
- {
- builder.Append("<Language>" + SecurityElement.Escape(hasLanguage.PreferredMetadataLanguage) + "</Language>");
- }
- if (!string.IsNullOrEmpty(hasLanguage.PreferredMetadataCountryCode))
- {
- builder.Append("<CountryCode>" + SecurityElement.Escape(hasLanguage.PreferredMetadataCountryCode) + "</CountryCode>");
- }
+ builder.Append("<Language>" + SecurityElement.Escape(item.PreferredMetadataLanguage) + "</Language>");
+ }
+ if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode))
+ {
+ builder.Append("<CountryCode>" + SecurityElement.Escape(item.PreferredMetadataCountryCode) + "</CountryCode>");
}
// Use original runtime here, actual file runtime later in MediaInfo
diff --git a/MediaBrowser.LocalMetadata/packages.config b/MediaBrowser.LocalMetadata/packages.config
new file mode 100644
index 000000000..fad6af08e
--- /dev/null
+++ b/MediaBrowser.LocalMetadata/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
index 17470d206..1ddb73d11 100644
--- a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
+++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
@@ -2,26 +2,38 @@
using MediaBrowser.Model.Configuration;
using System.Collections.Generic;
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.MediaEncoding.Configuration
{
public class EncodingConfigurationFactory : IConfigurationFactory
{
+ private readonly IFileSystem _fileSystem;
+
+ public EncodingConfigurationFactory(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
public IEnumerable<ConfigurationStore> GetConfigurations()
{
return new[]
{
- new EncodingConfigurationStore()
+ new EncodingConfigurationStore(_fileSystem)
};
}
}
public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration
{
- public EncodingConfigurationStore()
+ private readonly IFileSystem _fileSystem;
+
+ public EncodingConfigurationStore(IFileSystem fileSystem)
{
ConfigurationType = typeof(EncodingOptions);
Key = "encoding";
+ _fileSystem = fileSystem;
}
public void Validate(object oldConfig, object newConfig)
@@ -35,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Configuration
&& !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath))
{
// Validate
- if (!Directory.Exists(newPath))
+ if (!_fileSystem.DirectoryExists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index e9204ef5b..b488741d1 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index 181f147b4..912110c04 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -19,6 +19,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -65,7 +66,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
.CreateJob(options, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
- Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath));
encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;
@@ -112,7 +113,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
Logger.Info(commandLineLogMessage);
var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath));
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
@@ -144,7 +145,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);
// Wait for the file to exist before proceeeding
- while (!File.Exists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
+ while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
{
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
@@ -342,9 +343,55 @@ namespace MediaBrowser.MediaEncoding.Encoder
inputModifier += " -re";
}
+ var videoDecoder = GetVideoDecoder(job);
+ if (!string.IsNullOrWhiteSpace(videoDecoder))
+ {
+ inputModifier += " " + videoDecoder;
+ }
+
return inputModifier;
}
+ /// <summary>
+ /// Gets the name of the output video codec
+ /// </summary>
+ /// <param name="state">The state.</param>
+ /// <returns>System.String.</returns>
+ protected string GetVideoDecoder(EncodingJob state)
+ {
+ if (string.Equals(GetEncodingOptions().HardwareVideoDecoder, "qsv", StringComparison.OrdinalIgnoreCase))
+ {
+ if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
+ {
+ switch (state.MediaSource.VideoStream.Codec.ToLower())
+ {
+ case "avc":
+ case "h264":
+ if (MediaEncoder.SupportsDecoder("h264_qsv"))
+ {
+ return "-c:v h264_qsv ";
+ }
+ break;
+ case "mpeg2video":
+ if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
+ {
+ return "-c:v mpeg2_qsv ";
+ }
+ break;
+ case "vc1":
+ if (MediaEncoder.SupportsDecoder("vc1_qsv"))
+ {
+ return "-c:v vc1_qsv ";
+ }
+ break;
+ }
+ }
+ }
+
+ // leave blank so ffmpeg will decide
+ return null;
+ }
+
private string GetUserAgentParam(EncodingJob job)
{
string useragent = null;
@@ -422,7 +469,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
if (!(job.VideoType == VideoType.Iso && job.IsoMount == null))
{
- inputPath = MediaEncoderHelpers.GetInputArgument(job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
+ inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames);
}
}
@@ -436,7 +483,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false);
}
- if (state.MediaSource.RequiresOpening)
+ if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.LiveStreamId))
{
var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 806910d89..07626db33 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public bool EnableMpegtsM2TsMode { get; set; }
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
public long? EncodingDurationTicks { get; set; }
- public string LiveTvStreamId { get; set; }
+ public string LiveStreamId { get; set; }
public long? RunTimeTicks;
public string ItemType { get; set; }
@@ -368,6 +368,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ public string TargetVideoCodecTag
+ {
+ get
+ {
+ var stream = VideoStream;
+ return !Options.Static
+ ? null
+ : stream == null ? null : stream.CodecTag;
+ }
+ }
+
public bool? IsTargetAnamorphic
{
get
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 476d9166b..692fe2b6a 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -326,26 +326,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <returns>System.Nullable{System.Int32}.</returns>
private int? GetNumAudioChannelsParam(EncodingJobOptions request, MediaStream audioStream, string outputAudioCodec)
{
- if (audioStream != null)
+ var inputChannels = audioStream == null
+ ? null
+ : audioStream.Channels;
+
+ if (inputChannels <= 0)
{
- var codec = outputAudioCodec ?? string.Empty;
+ inputChannels = null;
+ }
- if (audioStream.Channels > 2 && codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
- {
- // wmav2 currently only supports two channel output
- return 2;
- }
+ 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);
}
if (request.MaxAudioChannels.HasValue)
{
- if (audioStream != null && audioStream.Channels.HasValue)
+ if (inputChannels.HasValue)
{
- return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
+ return Math.Min(request.MaxAudioChannels.Value, inputChannels.Value);
}
+ var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1
+ ? 2
+ : 6;
+
// 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, 5);
+ return Math.Min(request.MaxAudioChannels.Value, channelLimit);
}
return request.AudioChannels;
@@ -519,6 +529,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
+ if (videoStream.IsAnamorphic ?? false)
+ {
+ return false;
+ }
+
// Can't stream copy if we're burning in subtitles
if (request.SubtitleStreamIndex.HasValue)
{
@@ -735,7 +750,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.IsTargetCabac,
state.TargetRefFrames,
state.TargetVideoStreamCount,
- state.TargetAudioStreamCount);
+ state.TargetAudioStreamCount,
+ state.TargetVideoCodecTag);
if (mediaProfile != null)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 4fcc71f97..c8361ea04 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -22,6 +22,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
@@ -97,6 +98,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
FFMpegPath = ffMpegPath;
}
+ public void SetAvailableEncoders(List<string> list)
+ {
+
+ }
+
+ private List<string> _decoders = new List<string>();
+ public void SetAvailableDecoders(List<string> list)
+ {
+ _decoders = list.ToList();
+ }
+
+ public bool SupportsDecoder(string decoder)
+ {
+ return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
+ }
+
/// <summary>
/// Gets the encoder path.
/// </summary>
@@ -116,7 +133,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
- var inputFiles = MediaEncoderHelpers.GetInputArgument(request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
+ var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile;
@@ -199,10 +216,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
using (var processWrapper = new ProcessWrapper(process, this, _logger))
{
+ await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
try
{
StartProcess(processWrapper);
@@ -222,53 +239,55 @@ namespace MediaBrowser.MediaEncoding.Encoder
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
- if (result != null)
+ if (result.streams == null && result.format == null)
{
- if (result.streams != null)
+ throw new ApplicationException("ffprobe failed - streams and format are both null.");
+ }
+
+ if (result.streams != null)
+ {
+ // Normalize aspect ratio if invalid
+ foreach (var stream in result.streams)
{
- // Normalize aspect ratio if invalid
- foreach (var stream in result.streams)
+ if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.display_aspect_ratio = string.Empty;
- }
- if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.sample_aspect_ratio = string.Empty;
- }
+ stream.display_aspect_ratio = string.Empty;
+ }
+ if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.sample_aspect_ratio = string.Empty;
}
}
+ }
- var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+ var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
- if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
+ if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
+ {
+ if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue)
{
- if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue)
+ foreach (var stream in mediaInfo.MediaStreams)
{
- foreach (var stream in mediaInfo.MediaStreams)
+ if (EnableKeyframeExtraction(mediaInfo, stream))
{
- if (EnableKeyframeExtraction(mediaInfo, stream))
+ try
{
- try
- {
- stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting key frame interval", ex);
- }
+ stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting key frame interval", ex);
}
}
}
}
-
- return mediaInfo;
}
+
+ return mediaInfo;
}
catch
{
@@ -330,7 +349,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
EnableRaisingEvents = true
};
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
using (process)
{
@@ -356,7 +375,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
process.WaitForExit();
- _logger.Debug("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds);
+ _logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds);
//_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray()));
return lines;
}
@@ -483,9 +502,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- // TODO: Output in webp for smaller sizes
- // -f image2 -f webp
-
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
var args = useIFrame ? string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) :
string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
@@ -520,10 +536,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
using (var processWrapper = new ProcessWrapper(process, this, _logger))
{
+ await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
bool ranToCompletion;
var memoryStream = new MemoryStream();
@@ -605,7 +621,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
}
- Directory.CreateDirectory(targetDirectory);
+ FileSystem.CreateDirectory(targetDirectory);
var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
var args = string.Format("-i {0} -threads 1 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
@@ -879,4 +895,4 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 49eed9ee5..127145aec 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using System;
using System.IO;
+using CommonIO;
namespace MediaBrowser.MediaEncoding.Encoder
{
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index de05d9ffd..1f74994e5 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -12,7 +12,6 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -40,9 +39,16 @@
<Reference Include="BDInfo">
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\BDInfo.dll</HintPath>
</Reference>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="DvdLib">
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
</Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 0226dbc5a..7e9fa151b 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using CommonIO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
@@ -129,6 +130,7 @@ namespace MediaBrowser.MediaEncoding.Probing
var stream = new MediaStream
{
Codec = streamInfo.codec_name,
+ CodecTag = streamInfo.codec_tag_string,
Profile = streamInfo.profile,
Level = streamInfo.level,
Index = streamInfo.index,
@@ -148,7 +150,11 @@ namespace MediaBrowser.MediaEncoding.Probing
if (!string.IsNullOrEmpty(streamInfo.sample_rate))
{
- stream.SampleRate = int.Parse(streamInfo.sample_rate, _usCulture);
+ int value;
+ if (int.TryParse(streamInfo.sample_rate, NumberStyles.Any, _usCulture, out value))
+ {
+ stream.SampleRate = value;
+ }
}
stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout);
@@ -189,12 +195,21 @@ namespace MediaBrowser.MediaEncoding.Probing
if (!string.IsNullOrEmpty(streamInfo.bit_rate))
{
- bitrate = int.Parse(streamInfo.bit_rate, _usCulture);
+ int value;
+ if (int.TryParse(streamInfo.bit_rate, NumberStyles.Any, _usCulture, out value))
+ {
+ bitrate = value;
+ }
}
- else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
+
+ if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
{
// If the stream info doesn't have a bitrate get the value from the media format info
- bitrate = int.Parse(formatInfo.bit_rate, _usCulture);
+ int value;
+ if (int.TryParse(formatInfo.bit_rate, NumberStyles.Any, _usCulture, out value))
+ {
+ bitrate = value;
+ }
}
if (bitrate > 0)
@@ -516,12 +531,25 @@ namespace MediaBrowser.MediaEncoding.Probing
FetchStudios(audio, tags, "label");
// These support mulitple values, but for now we only store the first.
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id")));
+ var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"));
+ if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mb);
+
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"));
+ if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzArtist, mb);
+
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"));
+ if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, mb);
+
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"));
+ if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mb);
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id")));
- audio.SetProviderId(MetadataProviders.MusicBrainzTrack, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id")));
+ mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id"));
+ if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID"));
+ audio.SetProviderId(MetadataProviders.MusicBrainzTrack, mb);
}
private string GetMultipleMusicBrainzId(string value)
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
index d40d4afa7..2a6aa993c 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
@@ -69,7 +69,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
subEvent.Text = string.Join(ParserValues.NewLine, multiline);
subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
+ subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase);
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 9d43cafb8..ba44ed7dd 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -18,6 +18,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using UniversalDetector;
namespace MediaBrowser.MediaEncoding.Subtitles
@@ -49,7 +50,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
get
{
- return Path.Combine(_appPaths.CachePath, "subtitles");
+ return Path.Combine(_appPaths.DataPath, "subtitles");
}
}
@@ -183,7 +184,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- return File.OpenRead(path);
+ return _fileSystem.OpenRead(path);
}
private Encoding GetEncoding(string charset)
@@ -346,7 +347,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
try
{
- if (!File.Exists(outputPath))
+ if (!_fileSystem.FileExists(outputPath))
{
await ConvertTextSubtitleToSrtInternal(inputPath, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false);
}
@@ -383,7 +384,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
throw new ArgumentNullException("outputPath");
}
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, inputProtocol, cancellationToken).ConfigureAwait(false);
@@ -410,10 +411,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
};
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
+ _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath));
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
true);
@@ -466,7 +467,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
failed = true;
- if (File.Exists(outputPath))
+ if (_fileSystem.FileExists(outputPath))
{
try
{
@@ -479,7 +480,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
}
- else if (!File.Exists(outputPath))
+ else if (!_fileSystem.FileExists(outputPath))
{
failed = true;
}
@@ -515,7 +516,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
try
{
- if (!File.Exists(outputPath))
+ if (!_fileSystem.FileExists(outputPath))
{
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex,
outputCodec, outputPath, cancellationToken).ConfigureAwait(false);
@@ -540,7 +541,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
throw new ArgumentNullException("outputPath");
}
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
subtitleStreamIndex, outputCodec, outputPath);
@@ -566,7 +567,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath));
var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
true);
@@ -635,7 +636,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath);
}
}
- else if (!File.Exists(outputPath))
+ else if (!_fileSystem.FileExists(outputPath))
{
failed = true;
}
diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config
index 6e52b72b8..e8a1767e3 100644
--- a/MediaBrowser.MediaEncoding/packages.config
+++ b/MediaBrowser.MediaEncoding/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 7d813e903..40e532b79 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -1184,15 +1184,6 @@
<Compile Include="..\MediaBrowser.Model\Tasks\TaskTriggerInfo.cs">
<Link>Tasks\TaskTriggerInfo.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\AppTheme.cs">
- <Link>Themes\AppTheme.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\AppThemeInfo.cs">
- <Link>Themes\AppThemeInfo.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\ThemeImage.cs">
- <Link>Themes\ThemeImage.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Updates\CheckForUpdateResult.cs">
<Link>Updates\CheckForUpdateResult.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 8605a0ab3..09a7cde9d 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -1140,15 +1140,6 @@
<Compile Include="..\MediaBrowser.Model\Tasks\TaskTriggerInfo.cs">
<Link>Tasks\TaskTriggerInfo.cs</Link>
</Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\AppTheme.cs">
- <Link>Themes\AppTheme.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\AppThemeInfo.cs">
- <Link>Themes\AppThemeInfo.cs</Link>
- </Compile>
- <Compile Include="..\MediaBrowser.Model\Themes\ThemeImage.cs">
- <Link>Themes\ThemeImage.cs</Link>
- </Compile>
<Compile Include="..\MediaBrowser.Model\Updates\CheckForUpdateResult.cs">
<Link>Updates\CheckForUpdateResult.cs</Link>
</Compile>
diff --git a/MediaBrowser.Model/Configuration/DlnaOptions.cs b/MediaBrowser.Model/Configuration/DlnaOptions.cs
index 277102a50..c1974b877 100644
--- a/MediaBrowser.Model/Configuration/DlnaOptions.cs
+++ b/MediaBrowser.Model/Configuration/DlnaOptions.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Configuration
public int ClientDiscoveryIntervalSeconds { get; set; }
public int BlastAliveMessageIntervalSeconds { get; set; }
public string DefaultUserId { get; set; }
- public bool EnableEnhancedMovies { get; set; }
+ public bool EnableMovieFolders { get; set; }
public DlnaOptions()
{
@@ -19,7 +19,6 @@ namespace MediaBrowser.Model.Configuration
BlastAliveMessages = true;
ClientDiscoveryIntervalSeconds = 60;
BlastAliveMessageIntervalSeconds = 30;
- EnableEnhancedMovies = true;
}
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index 6d3894f02..77b894eb8 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -6,14 +6,13 @@ namespace MediaBrowser.Model.Configuration
public int EncodingThreadCount { get; set; }
public string TranscodingTempPath { get; set; }
public double DownMixAudioBoost { get; set; }
- public string H264Encoder { get; set; }
public bool EnableDebugLogging { get; set; }
public bool EnableThrottling { get; set; }
public int ThrottleThresholdInSeconds { get; set; }
+ public string HardwareVideoDecoder { get; set; }
public EncodingOptions()
{
- H264Encoder = "libx264";
DownMixAudioBoost = 2;
EnableThrottling = true;
ThrottleThresholdInSeconds = 120;
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 87b5e4fd7..dfcafa32d 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -45,12 +45,6 @@ namespace MediaBrowser.Model.Configuration
public bool EnableHttps { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether [enable user specific user views].
- /// </summary>
- /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
- public bool EnableUserSpecificUserViews { get; set; }
-
- /// <summary>
/// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
/// </summary>
/// <value>The value pointing to the file system where the ssl certiifcate is located..</value>
@@ -103,7 +97,13 @@ namespace MediaBrowser.Model.Configuration
/// </summary>
/// <value><c>true</c> if [disable startup scan]; otherwise, <c>false</c>.</value>
public bool DisableStartupScan { get; set; }
-
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [enable user views].
+ /// </summary>
+ /// <value><c>true</c> if [enable user views]; otherwise, <c>false</c>.</value>
+ public bool EnableUserViews { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether [enable library metadata sub folder].
/// </summary>
@@ -223,12 +223,18 @@ namespace MediaBrowser.Model.Configuration
public bool EnableWindowsShortcuts { get; set; }
public bool EnableVideoFrameByFrameAnalysis { get; set; }
-
+
+ public bool EnableDateLastRefresh { get; set; }
+
+ public string[] Migrations { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
public ServerConfiguration()
{
+ Migrations = new string[] {};
+
ImageSavingConvention = ImageSavingConvention.Compatible;
PublicPort = 8096;
PublicHttpsPort = 8920;
@@ -274,11 +280,6 @@ namespace MediaBrowser.Model.Configuration
InsecureApps9 = new[]
{
- "Chromecast",
- "iOS",
- "Unknown app",
- "iPad",
- "iPhone",
"Windows Phone"
};
@@ -581,4 +582,4 @@ namespace MediaBrowser.Model.Configuration
};
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Model/Devices/DeviceInfo.cs b/MediaBrowser.Model/Devices/DeviceInfo.cs
index 726e9d6e5..d8358977e 100644
--- a/MediaBrowser.Model/Devices/DeviceInfo.cs
+++ b/MediaBrowser.Model/Devices/DeviceInfo.cs
@@ -27,7 +27,10 @@ namespace MediaBrowser.Model.Devices
/// <value>The name.</value>
public string Name
{
- get { return string.IsNullOrEmpty(CustomName) ? ReportedName : CustomName; }
+ get
+ {
+ return string.IsNullOrEmpty(CustomName) ? ReportedName : CustomName;
+ }
}
/// <summary>
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index 793036f40..fef04647a 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -20,16 +20,11 @@ namespace MediaBrowser.Model.Dlna
bool? isCabac,
int? refFrames,
int? numVideoStreams,
- int? numAudioStreams)
+ int? numAudioStreams,
+ string videoCodecTag)
{
switch (condition.Property)
{
- case ProfileConditionValue.AudioProfile:
- // TODO: Implement
- return true;
- case ProfileConditionValue.Has64BitOffsets:
- // TODO: Implement
- return true;
case ProfileConditionValue.IsAnamorphic:
return IsConditionSatisfied(condition, isAnamorphic);
case ProfileConditionValue.IsCabac:
@@ -40,6 +35,8 @@ namespace MediaBrowser.Model.Dlna
return IsConditionSatisfied(condition, videoLevel);
case ProfileConditionValue.VideoProfile:
return IsConditionSatisfied(condition, videoProfile);
+ case ProfileConditionValue.VideoCodecTag:
+ return IsConditionSatisfied(condition, videoCodecTag);
case ProfileConditionValue.PacketLength:
return IsConditionSatisfied(condition, packetLength);
case ProfileConditionValue.VideoBitDepth:
@@ -59,7 +56,7 @@ namespace MediaBrowser.Model.Dlna
case ProfileConditionValue.VideoTimestamp:
return IsConditionSatisfied(condition, timestamp);
default:
- throw new ArgumentException("Unexpected condition on video file: " + condition.Property);
+ return true;
}
}
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index 62463d196..58d669c22 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -118,7 +118,8 @@ namespace MediaBrowser.Model.Dlna
bool? isCabac,
int? refFrames,
int? numVideoStreams,
- int? numAudioStreams)
+ int? numAudioStreams,
+ string videoCodecTag)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
@@ -159,7 +160,8 @@ namespace MediaBrowser.Model.Dlna
isCabac,
refFrames,
numVideoStreams,
- numAudioStreams);
+ numAudioStreams,
+ videoCodecTag);
List<string> orgPnValues = new List<string>();
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index fc508991e..6d4aa34a3 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -286,7 +286,8 @@ namespace MediaBrowser.Model.Dlna
bool? isCabac,
int? refFrames,
int? numVideoStreams,
- int? numAudioStreams)
+ int? numAudioStreams,
+ string videoCodecTag)
{
container = StringHelper.TrimStart((container ?? string.Empty), '.');
@@ -320,7 +321,7 @@ namespace MediaBrowser.Model.Dlna
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+ if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
{
anyOff = true;
break;
diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
index 7563ffb5a..4ad326e51 100644
--- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
+++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
@@ -20,6 +20,7 @@
IsCabac = 15,
NumAudioStreams = 16,
NumVideoStreams = 17,
- IsSecondaryAudio
+ IsSecondaryAudio = 18,
+ VideoCodecTag = 19
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 0335c43f0..1834e24fe 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -286,7 +286,7 @@ namespace MediaBrowser.Model.Dlna
}
else
{
- _logger.Debug("Profile: {0}, No direct play profiles found for Path: {1}",
+ _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
options.Profile.Name ?? "Unknown Profile",
item.Path ?? "Unknown path");
}
@@ -365,7 +365,7 @@ namespace MediaBrowser.Model.Dlna
bool isEligibleForDirectPlay = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options), subtitleStream, options, PlayMethod.DirectPlay);
bool isEligibleForDirectStream = IsEligibleForDirectPlay(item, options.GetMaxBitrate(), subtitleStream, options, PlayMethod.DirectStream);
- _logger.Debug("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
+ _logger.Info("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
options.Profile.Name ?? "Unknown Profile",
item.Path ?? "Unknown path",
isEligibleForDirectPlay,
@@ -538,7 +538,7 @@ namespace MediaBrowser.Model.Dlna
if (directPlay == null)
{
- _logger.Debug("Profile: {0}, No direct play profiles found for Path: {1}",
+ _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}",
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
@@ -571,6 +571,7 @@ namespace MediaBrowser.Model.Dlna
float? videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
bool? isAnamorphic = videoStream == null ? null : videoStream.IsAnamorphic;
bool? isCabac = videoStream == null ? null : videoStream.IsCabac;
+ string videoCodecTag = videoStream == null ? null : videoStream.CodecTag;
int? audioBitrate = audioStream == null ? null : audioStream.BitRate;
int? audioChannels = audioStream == null ? null : audioStream.Channels;
@@ -586,7 +587,7 @@ namespace MediaBrowser.Model.Dlna
// Check container conditions
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
{
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
@@ -598,7 +599,7 @@ namespace MediaBrowser.Model.Dlna
if (string.IsNullOrEmpty(videoCodec))
{
- _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown video codec. Path: {1}",
+ _logger.Info("Profile: {0}, DirectPlay=false. Reason=Unknown video codec. Path: {1}",
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
@@ -619,7 +620,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams, videoCodecTag))
{
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
@@ -633,7 +634,7 @@ namespace MediaBrowser.Model.Dlna
if (string.IsNullOrEmpty(audioCodec))
{
- _logger.Debug("Profile: {0}, DirectPlay=false. Reason=Unknown audio codec. Path: {1}",
+ _logger.Info("Profile: {0}, DirectPlay=false. Reason=Unknown audio codec. Path: {1}",
profile.Name ?? "Unknown Profile",
mediaSource.Path ?? "Unknown path");
@@ -693,7 +694,7 @@ namespace MediaBrowser.Model.Dlna
private void LogConditionFailure(DeviceProfile profile, string type, ProfileCondition condition, MediaSourceInfo mediaSource)
{
- _logger.Debug("Profile: {0}, DirectPlay=false. Reason={1}.{2} Condition: {3}. ConditionValue: {4}. IsRequired: {5}. Path: {6}",
+ _logger.Info("Profile: {0}, DirectPlay=false. Reason={1}.{2} Condition: {3}. ConditionValue: {4}. IsRequired: {5}. Path: {6}",
type,
profile.Name ?? "Unknown Profile",
condition.Property,
@@ -715,7 +716,7 @@ namespace MediaBrowser.Model.Dlna
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
{
- _logger.Debug("Not eligible for {0} due to unsupported subtitles", playMethod);
+ _logger.Info("Not eligible for {0} due to unsupported subtitles", playMethod);
return false;
}
}
@@ -770,12 +771,12 @@ namespace MediaBrowser.Model.Dlna
{
return profile;
}
- }
- // For sync we can handle the longer extraction times
- if (context == EncodingContext.Static && subtitleStream.IsTextSubtitleStream)
- {
- return profile;
+ // For sync we can handle the longer extraction times
+ if (context == EncodingContext.Static && subtitleStream.IsTextSubtitleStream)
+ {
+ return profile;
+ }
}
}
}
@@ -794,7 +795,7 @@ namespace MediaBrowser.Model.Dlna
return true;
}
- _logger.Debug("Bitrate exceeds DirectPlay limit");
+ _logger.Info("Bitrate exceeds DirectPlay limit");
return false;
}
@@ -966,8 +967,6 @@ namespace MediaBrowser.Model.Dlna
}
break;
}
- default:
- throw new ArgumentException("Unrecognized ProfileConditionValue");
}
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 8f7412097..50d1cdfc8 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -490,6 +490,21 @@ namespace MediaBrowser.Model.Dlna
}
/// <summary>
+ /// Gets the target video codec tag.
+ /// </summary>
+ /// <value>The target video codec tag.</value>
+ public string TargetVideoCodecTag
+ {
+ get
+ {
+ MediaStream stream = TargetVideoStream;
+ return !IsDirectStream
+ ? null
+ : stream == null ? null : stream.CodecTag;
+ }
+ }
+
+ /// <summary>
/// Predicts the audio bitrate that will be in the output stream
/// </summary>
public int? TargetAudioBitrate
diff --git a/MediaBrowser.Model/Dlna/SubtitleProfile.cs b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
index 1795c374a..0723de222 100644
--- a/MediaBrowser.Model/Dlna/SubtitleProfile.cs
+++ b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
@@ -28,15 +28,20 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- public bool SupportsLanguage(string language)
+ public bool SupportsLanguage(string subLanguage)
{
- if (string.IsNullOrEmpty(language))
+ if (string.IsNullOrEmpty(Language))
{
- language = "und";
+ return true;
+ }
+
+ if (string.IsNullOrEmpty(subLanguage))
+ {
+ subLanguage = "und";
}
List<string> languages = GetLanguages();
- return languages.Count == 0 || ListHelper.ContainsIgnoreCase(languages, language);
+ return languages.Count == 0 || ListHelper.ContainsIgnoreCase(languages, subLanguage);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index a1c075563..ff67db1b6 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -67,6 +67,8 @@ namespace MediaBrowser.Model.Dto
public bool? CanDelete { get; set; }
public bool? CanDownload { get; set; }
+ public bool? HasSubtitles { get; set; }
+
public string PreferredMetadataLanguage { get; set; }
public string PreferredMetadataCountryCode { get; set; }
@@ -74,8 +76,6 @@ namespace MediaBrowser.Model.Dto
public string ShareUrl { get; set; }
public float? Metascore { get; set; }
-
- public bool? IsUnidentified { get; set; }
public bool? HasDynamicCategories { get; set; }
public int? AnimeSeriesIndex { get; set; }
@@ -278,12 +278,6 @@ namespace MediaBrowser.Model.Dto
public int? ProductionYear { get; set; }
/// <summary>
- /// Gets or sets the season count.
- /// </summary>
- /// <value>The season count.</value>
- public int? SeasonCount { get; set; }
-
- /// <summary>
/// Gets or sets the players supported by a game.
/// </summary>
/// <value>The players.</value>
@@ -1113,12 +1107,6 @@ namespace MediaBrowser.Model.Dto
public DateTime? StartDate { get; set; }
/// <summary>
- /// Gets or sets the original air date.
- /// </summary>
- /// <value>The original air date.</value>
- public DateTime? OriginalAirDate { get; set; }
-
- /// <summary>
/// Gets or sets the completion percentage.
/// </summary>
/// <value>The completion percentage.</value>
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 519d3a04c..79d1df911 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -19,6 +19,12 @@ namespace MediaBrowser.Model.Entities
public string Codec { get; set; }
/// <summary>
+ /// Gets or sets the codec tag.
+ /// </summary>
+ /// <value>The codec tag.</value>
+ public string CodecTag { get; set; }
+
+ /// <summary>
/// Gets or sets the language.
/// </summary>
/// <value>The language.</value>
diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
index d440f97bd..1161ab005 100644
--- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
+++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
@@ -32,5 +32,17 @@ namespace MediaBrowser.Model.Entities
{
Locations = new List<string>();
}
+
+ /// <summary>
+ /// Gets or sets the item identifier.
+ /// </summary>
+ /// <value>The item identifier.</value>
+ public string ItemId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the primary image item identifier.
+ /// </summary>
+ /// <value>The primary image item identifier.</value>
+ public string PrimaryImageItemId { get; set; }
}
}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 19c5c833a..1386854bb 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -12,10 +12,9 @@
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<FodyPath>..\packages\Fody.1.19.1.0</FodyPath>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
+ <ReleaseVersion>
+ </ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -26,7 +25,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -35,7 +33,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -44,15 +41,11 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
- <SignAssembly>false</SignAssembly>
- </PropertyGroup>
- <PropertyGroup>
<AssemblyOriginatorKeyFile>MediaBrowser.Model.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
@@ -408,9 +401,6 @@
<Compile Include="Sync\SyncTarget.cs" />
<Compile Include="System\LogFile.cs" />
<Compile Include="System\PublicSystemInfo.cs" />
- <Compile Include="Themes\AppTheme.cs" />
- <Compile Include="Themes\AppThemeInfo.cs" />
- <Compile Include="Themes\ThemeImage.cs" />
<Compile Include="Updates\CheckForUpdateResult.cs" />
<Compile Include="Updates\PackageTargetSystem.cs" />
<Compile Include="Updates\InstallationInfo.cs" />
@@ -465,7 +455,7 @@
<HintPath>..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll</HintPath>
<Private>False</Private>
</Reference>
- <Reference Include="System.XML" />
+ <Reference Include="System.Xml" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index 0362b7aed..eea561f72 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -36,6 +36,11 @@
CanDownload,
/// <summary>
+ /// The channel information
+ /// </summary>
+ ChannelInfo,
+
+ /// <summary>
/// The chapters
/// </summary>
Chapters,
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index c8209baa8..e3e8c7be2 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -39,11 +39,11 @@ namespace MediaBrowser.Model.System
public bool HasPendingRestart { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether [supports synchronize].
+ /// Gets or sets a value indicating whether [supports library monitor].
/// </summary>
- /// <value><c>true</c> if [supports synchronize]; otherwise, <c>false</c>.</value>
- public bool SupportsSync { get; set; }
-
+ /// <value><c>true</c> if [supports library monitor]; otherwise, <c>false</c>.</value>
+ public bool SupportsLibraryMonitor { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether this instance is network deployed.
/// </summary>
diff --git a/MediaBrowser.Model/Themes/AppTheme.cs b/MediaBrowser.Model/Themes/AppTheme.cs
deleted file mode 100644
index 527f1de72..000000000
--- a/MediaBrowser.Model/Themes/AppTheme.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.Themes
-{
- public class AppTheme
- {
- public string AppName { get; set; }
-
- public string Name { get; set; }
-
- public Dictionary<string, string> Options { get; set; }
-
- public List<ThemeImage> Images { get; set; }
-
- public AppTheme()
- {
- Options = new Dictionary<string, string>();
-
- Images = new List<ThemeImage>();
- }
- }
-}
diff --git a/MediaBrowser.Model/Themes/AppThemeInfo.cs b/MediaBrowser.Model/Themes/AppThemeInfo.cs
deleted file mode 100644
index bc359530a..000000000
--- a/MediaBrowser.Model/Themes/AppThemeInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace MediaBrowser.Model.Themes
-{
- public class AppThemeInfo
- {
- public string AppName { get; set; }
-
- public string Name { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/Themes/ThemeImage.cs b/MediaBrowser.Model/Themes/ThemeImage.cs
deleted file mode 100644
index 2fe0820ae..000000000
--- a/MediaBrowser.Model/Themes/ThemeImage.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-
-namespace MediaBrowser.Model.Themes
-{
- public class ThemeImage
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the cache tag.
- /// </summary>
- /// <value>The cache tag.</value>
- public string CacheTag { get; set; }
- }
-}
diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs
index 311082d96..0d030c039 100644
--- a/MediaBrowser.Providers/Books/BookMetadataService.cs
+++ b/MediaBrowser.Providers/Books/BookMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Books
{
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index 8b405302e..cba19a5c2 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.BoxSets
{
diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
index 0e7050741..ae6199a75 100644
--- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
+++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
@@ -18,6 +18,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.BoxSets
{
@@ -156,7 +157,7 @@ namespace MediaBrowser.Providers.BoxSets
var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_json.SerializeToFile(mainResult, dataFilePath);
}
diff --git a/MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs b/MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs
index 9d80559f1..9a1a993d9 100644
--- a/MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs
+++ b/MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using CommonIO;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
index faa35b379..6fd7b2539 100644
--- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Channels
{
diff --git a/MediaBrowser.Providers/Channels/VideoChannelItemMetadataService.cs b/MediaBrowser.Providers/Channels/VideoChannelItemMetadataService.cs
index 1e7b5aca8..597ae5e10 100644
--- a/MediaBrowser.Providers/Channels/VideoChannelItemMetadataService.cs
+++ b/MediaBrowser.Providers/Channels/VideoChannelItemMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Channels
{
diff --git a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
index 13e486ae9..270867f90 100644
--- a/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
+++ b/MediaBrowser.Providers/Folders/DefaultImageProvider.cs
@@ -77,11 +77,11 @@ namespace MediaBrowser.Providers.Folders
if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "books.png";
+ //return urlPrefix + "books.png";
}
if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "games.png";
+ //return urlPrefix + "games.png";
}
if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
{
@@ -109,23 +109,23 @@ namespace MediaBrowser.Providers.Folders
}
if (string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "playlists.png";
+ //return urlPrefix + "playlists.png";
}
if (string.Equals(viewType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "homevideos.png";
+ //return urlPrefix + "homevideos.png";
}
if (string.Equals(viewType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "musicvideos.png";
+ //return urlPrefix + "musicvideos.png";
}
if (string.Equals(viewType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
{
- return urlPrefix + "generic.png";
+ //return urlPrefix + "generic.png";
}
if (string.IsNullOrWhiteSpace(viewType))
{
- return urlPrefix + "generic.png";
+ //return urlPrefix + "generic.png";
}
return null;
@@ -142,10 +142,17 @@ namespace MediaBrowser.Providers.Folders
if (view != null)
{
- return true;
+ return !string.IsNullOrWhiteSpace(GetImageUrl(view.ViewType));
+ }
+
+ var folder = item as ICollectionFolder;
+
+ if (folder != null)
+ {
+ return !string.IsNullOrWhiteSpace(GetImageUrl(folder.CollectionType));
}
- return item is ICollectionFolder;
+ return false;
}
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
index d54093da6..c7b60afcc 100644
--- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Folders
{
diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
index 70b86830f..a9366a9d3 100644
--- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Folders
{
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
index e994e27c3..9d4b90ff3 100644
--- a/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
+++ b/MediaBrowser.Providers/GameGenres/GameGenreImageProvider.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.GameGenres
{
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
index 957596a30..676c08c56 100644
--- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
+++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.GameGenres
{
diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs
index b9403aaa6..26359dfb8 100644
--- a/MediaBrowser.Providers/Games/GameMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Games
{
diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
index 24786034d..112b01957 100644
--- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Games
{
diff --git a/MediaBrowser.Providers/Genres/GenreImageProvider.cs b/MediaBrowser.Providers/Genres/GenreImageProvider.cs
index 5d5c2873a..373f59acc 100644
--- a/MediaBrowser.Providers/Genres/GenreImageProvider.cs
+++ b/MediaBrowser.Providers/Genres/GenreImageProvider.cs
@@ -11,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Genres
{
diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
index 5cdd6d847..a93c33e66 100644
--- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs
+++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Genres
{
diff --git a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
index 72df3697a..fc818b690 100644
--- a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
+++ b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.ImagesByName
{
@@ -24,7 +25,7 @@ namespace MediaBrowser.Providers.ImagesByName
/// <returns>Task.</returns>
public static async Task EnsureList(string url, string file, IHttpClient httpClient, IFileSystem fileSystem, SemaphoreSlim semaphore, CancellationToken cancellationToken)
{
- var fileInfo = new FileInfo(file);
+ var fileInfo = fileSystem.GetFileInfo(file);
if (!fileInfo.Exists || (DateTime.UtcNow - fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays > 1)
{
@@ -40,9 +41,9 @@ namespace MediaBrowser.Providers.ImagesByName
}).ConfigureAwait(false);
- Directory.CreateDirectory(Path.GetDirectoryName(file));
+ fileSystem.CreateDirectory(Path.GetDirectoryName(file));
- File.Copy(temp, file, true);
+ fileSystem.CopyFile(temp, file, true);
}
finally
{
diff --git a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
index b3d9d6a72..0798f3ef4 100644
--- a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.LiveTv
{
diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
index 231017cd9..31af0916c 100644
--- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.LiveTv
{
diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
index 8576993fd..385f455b2 100644
--- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.LiveTv
{
diff --git a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
index 4d8b27285..e80768ff8 100644
--- a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.LiveTv
{
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 22178434f..9d183c880 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Manager
{
@@ -122,35 +123,36 @@ namespace MediaBrowser.Providers.Manager
new[] { GetCacheKeyPath(item, type, mimeType, internalCacheKey) } :
GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
+ var retryPaths = !string.IsNullOrEmpty(internalCacheKey) ?
+ new[] { GetCacheKeyPath(item, type, mimeType, internalCacheKey) } :
+ GetSavePaths(item, type, imageIndex, mimeType, false);
+
// If there are more than one output paths, the stream will need to be seekable
- if (paths.Length > 1 && !source.CanSeek)
+ var memoryStream = new MemoryStream();
+ using (source)
{
- var memoryStream = new MemoryStream();
- using (source)
- {
- await source.CopyToAsync(memoryStream).ConfigureAwait(false);
- }
- memoryStream.Position = 0;
- source = memoryStream;
+ await source.CopyToAsync(memoryStream).ConfigureAwait(false);
}
- var currentPath = GetCurrentImagePath(item, type, index);
+ source = memoryStream;
+
+ var currentImage = GetCurrentImage(item, type, index);
using (source)
{
- var isFirst = true;
+ var currentPathIndex = 0;
foreach (var path in paths)
{
- // Seek back to the beginning
- if (!isFirst)
+ source.Position = 0;
+ string retryPath = null;
+ if (paths.Length == retryPaths.Length)
{
- source.Position = 0;
+ retryPath = retryPaths[currentPathIndex];
}
+ await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false);
- await SaveImageToLocation(source, path, cancellationToken).ConfigureAwait(false);
-
- isFirst = false;
+ currentPathIndex++;
}
}
@@ -158,8 +160,10 @@ namespace MediaBrowser.Providers.Manager
SetImagePath(item, type, imageIndex, paths[0]);
// Delete the current path
- if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
+ if (currentImage != null && currentImage.IsLocalFile && !paths.Contains(currentImage.Path, StringComparer.OrdinalIgnoreCase))
{
+ var currentPath = currentImage.Path;
+
_libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
try
@@ -184,6 +188,31 @@ namespace MediaBrowser.Providers.Manager
}
}
+ private async Task SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken cancellationToken)
+ {
+ try
+ {
+ await SaveImageToLocation(source, path, cancellationToken).ConfigureAwait(false);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ var retry = !string.IsNullOrWhiteSpace(retryPath) &&
+ !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase);
+
+ if (retry)
+ {
+ _logger.Error("UnauthorizedAccessException - Access to path {0} is denied. Will retry saving to {1}", path, retryPath);
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ source.Position = 0;
+ await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
+ }
+
private string GetCacheKeyPath(IHasImages item, ImageType type, string mimeType, string key)
{
var extension = MimeTypes.ToExtension(mimeType);
@@ -208,7 +237,7 @@ namespace MediaBrowser.Providers.Manager
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
// If the file is currently hidden we'll have to remove that or the save will fail
var file = new FileInfo(path);
@@ -236,11 +265,6 @@ namespace MediaBrowser.Providers.Manager
file.Attributes |= FileAttributes.Hidden;
}
}
- catch (UnauthorizedAccessException ex)
- {
- _logger.Error("Error saving image to {0}", ex, path);
- throw new Exception(string.Format("Error saving image to {0}", path), ex);
- }
finally
{
_libraryMonitor.ReportFileSystemChangeComplete(path, false);
@@ -279,9 +303,9 @@ namespace MediaBrowser.Providers.Manager
/// or
/// imageIndex
/// </exception>
- private string GetCurrentImagePath(IHasImages item, ImageType type, int imageIndex)
+ private ItemImageInfo GetCurrentImage(IHasImages item, ImageType type, int imageIndex)
{
- return item.GetImagePath(type, imageIndex);
+ return item.GetImageInfo(type, imageIndex);
}
/// <summary>
@@ -296,7 +320,7 @@ namespace MediaBrowser.Providers.Manager
/// imageIndex</exception>
private void SetImagePath(IHasImages item, ImageType type, int? imageIndex, string path)
{
- item.SetImagePath(type, imageIndex ?? 0, new FileInfo(path));
+ item.SetImagePath(type, imageIndex ?? 0, _fileSystem.GetFileInfo(path));
}
/// <summary>
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 92fc1c2a8..838306e13 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -16,6 +16,8 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Providers.Manager
{
@@ -137,11 +139,24 @@ namespace MediaBrowser.Providers.Manager
{
if (!string.IsNullOrEmpty(response.Path))
{
- var mimeType = MimeTypes.GetMimeType(response.Path);
-
- var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
-
- await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
+ if (response.Protocol == MediaProtocol.Http)
+ {
+ _logger.Debug("Setting image url into item {0}", item.Id);
+ item.SetImage(new ItemImageInfo
+ {
+ Path = response.Path,
+ Type = imageType
+
+ }, 0);
+ }
+ else
+ {
+ var mimeType = MimeTypes.GetMimeType(response.Path);
+
+ var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
+
+ await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
+ }
}
else
{
@@ -163,7 +178,6 @@ namespace MediaBrowser.Providers.Manager
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
- result.Status = ProviderRefreshStatus.CompletedWithErrors;
_logger.ErrorException("Error in {0}", ex, provider.Name);
}
}
@@ -302,7 +316,6 @@ namespace MediaBrowser.Providers.Manager
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
- result.Status = ProviderRefreshStatus.CompletedWithErrors;
_logger.ErrorException("Error in {0}", ex, provider.Name);
}
}
@@ -358,7 +371,7 @@ namespace MediaBrowser.Providers.Manager
if (deleted)
{
- item.ValidateImages(new DirectoryService(_logger));
+ item.ValidateImages(new DirectoryService(_logger, _fileSystem));
}
}
@@ -392,10 +405,13 @@ namespace MediaBrowser.Providers.Manager
else
{
var existing = item.GetImageInfo(type, 0);
- if (existing != null && !File.Exists(existing.Path))
+ if (existing != null)
{
- item.RemoveImage(existing);
- changed = true;
+ if (existing.IsLocalFile && !_fileSystem.FileExists(existing.Path))
+ {
+ item.RemoveImage(existing);
+ changed = true;
+ }
}
}
}
@@ -452,6 +468,13 @@ namespace MediaBrowser.Providers.Manager
var url = image.Url;
+ if (EnableImageStub(item, type))
+ {
+ SaveImageStub(item, type, url);
+ result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
+ return true;
+ }
+
try
{
var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false);
@@ -475,6 +498,28 @@ namespace MediaBrowser.Providers.Manager
return false;
}
+ private bool EnableImageStub(IHasImages item, ImageType type)
+ {
+ if (item.LocationType == LocationType.Remote || item.LocationType == LocationType.Virtual)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void SaveImageStub(IHasImages item, ImageType imageType, string url)
+ {
+ var newIndex = item.AllowsMultipleImages(imageType) ? item.GetImages(imageType).Count() : 0;
+
+ item.SetImage(new ItemImageInfo
+ {
+ Path = url,
+ Type = imageType
+
+ }, newIndex);
+ }
+
private async Task DownloadBackdrops(IHasImages item, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken)
{
foreach (var image in images.Where(i => i.Type == imageType))
@@ -491,6 +536,13 @@ namespace MediaBrowser.Providers.Manager
var url = image.Url;
+ if (EnableImageStub(item, imageType))
+ {
+ SaveImageStub(item, imageType, url);
+ result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
+ return;
+ }
+
try
{
var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index cddc6f894..6860aeff3 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -11,6 +11,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.Providers.Manager
{
@@ -81,7 +84,7 @@ namespace MediaBrowser.Providers.Manager
/// <returns>ProviderResult.</returns>
protected MetadataStatus GetLastResult(IHasMetadata item)
{
- if (item.DateLastSaved == default(DateTime))
+ if (GetLastRefreshDate(item) == default(DateTime))
{
return new MetadataStatus { ItemId = item.Id };
}
@@ -97,7 +100,6 @@ namespace MediaBrowser.Providers.Manager
var updateType = ItemUpdateType.None;
var refreshResult = GetLastResult(item);
refreshResult.LastErrorMessage = string.Empty;
- refreshResult.LastStatus = ProviderRefreshStatus.Success;
var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
var localImagesFailed = false;
@@ -117,7 +119,7 @@ namespace MediaBrowser.Providers.Manager
{
localImagesFailed = true;
Logger.ErrorException("Error validating images for {0}", ex, item.Path ?? item.Name ?? "Unknown name");
- refreshResult.AddStatus(ProviderRefreshStatus.Failure, ex.Message);
+ refreshResult.AddStatus(ex.Message);
}
var metadataResult = new MetadataResult<TItemType>
@@ -141,15 +143,22 @@ namespace MediaBrowser.Providers.Manager
if (providers.Count > 0)
{
- var id = await CreateInitialLookupInfo(itemOfType, cancellationToken).ConfigureAwait(false);
+ var id = itemOfType.GetLookupInfo();
+
+ await FindIdentities(id, cancellationToken).ConfigureAwait(false);
var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);
updateType = updateType | result.UpdateType;
- refreshResult.AddStatus(result.Status, result.ErrorMessage);
- refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
-
- MergeIdentities(itemOfType, id);
+ refreshResult.AddStatus(result.ErrorMessage);
+ if (result.Failures == 0)
+ {
+ refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
+ }
+ else
+ {
+ refreshResult.SetDateLastMetadataRefresh(null);
+ }
}
}
@@ -163,16 +172,25 @@ namespace MediaBrowser.Providers.Manager
var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);
updateType = updateType | result.UpdateType;
- refreshResult.AddStatus(result.Status, result.ErrorMessage);
- refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
+ refreshResult.AddStatus(result.ErrorMessage);
+ if (result.Failures == 0)
+ {
+ refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
+ }
+ else
+ {
+ refreshResult.SetDateLastImagesRefresh(null);
+ }
}
}
- var beforeSaveResult = await BeforeSave(itemOfType, item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false);
+ var isFirstRefresh = GetLastRefreshDate(item) == default(DateTime);
+
+ var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false);
updateType = updateType | beforeSaveResult;
// Save if changes were made, or it's never been saved before
- if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata)
+ if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata)
{
// If any of these properties are set then make sure the updateType is not None, just to force everything to save
if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata)
@@ -180,6 +198,11 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | ItemUpdateType.MetadataDownload;
}
+ if (refreshOptions.MetadataRefreshMode >= MetadataRefreshMode.Default && refreshOptions.ImageRefreshMode >= ImageRefreshMode.Default)
+ {
+ item.DateLastRefreshed = DateTime.UtcNow;
+ }
+
// Save to database
await SaveItem(metadataResult, updateType, cancellationToken).ConfigureAwait(false);
}
@@ -194,6 +217,38 @@ namespace MediaBrowser.Providers.Manager
return updateType;
}
+ private async Task FindIdentities(TIdType id, CancellationToken cancellationToken)
+ {
+ try
+ {
+ await ItemIdentifier<TIdType>.FindIdentities(id, ProviderManager, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error in FindIdentities", ex);
+ }
+ }
+
+ private DateTime GetLastRefreshDate(IHasMetadata item)
+ {
+ if (item.DateLastRefreshed != default(DateTime))
+ {
+ return item.DateLastRefreshed;
+ }
+
+ if (ServerConfigurationManager.Configuration.EnableDateLastRefresh)
+ {
+ return item.DateLastRefreshed;
+ }
+
+ if (item is BoxSet || (item is IItemByName && !(item is MusicArtist)))
+ {
+ return item.DateLastRefreshed;
+ }
+
+ return item.DateLastSaved;
+ }
+
protected async Task SaveItem(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken)
{
if (result.Item.SupportsPeople && result.People != null)
@@ -210,15 +265,6 @@ namespace MediaBrowser.Providers.Manager
return _cachedTask;
}
- private void MergeIdentities(TItemType item, TIdType id)
- {
- var hasIdentity = id as IHasIdentities<IItemIdentity>;
- if (hasIdentity != null)
- {
- item.Identities = hasIdentity.Identities.ToList();
- }
- }
-
private readonly Task<ItemUpdateType> _cachedResult = Task.FromResult(ItemUpdateType.None);
/// <summary>
/// Befores the save.
@@ -370,8 +416,6 @@ namespace MediaBrowser.Providers.Manager
Item = CreateNew()
};
temp.Item.Path = item.Path;
- var successfulProviderCount = 0;
- var failedProviderCount = 0;
var userDataList = new List<UserItemData>();
@@ -382,10 +426,8 @@ namespace MediaBrowser.Providers.Manager
.ConfigureAwait(false);
refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType;
- refreshResult.Status = remoteResult.Status;
refreshResult.ErrorMessage = remoteResult.ErrorMessage;
- successfulProviderCount += remoteResult.Successes;
- failedProviderCount += remoteResult.Failures;
+ refreshResult.Failures += remoteResult.Failures;
}
var hasLocalMetadata = false;
@@ -421,7 +463,6 @@ namespace MediaBrowser.Providers.Manager
{
hasLocalMetadata = true;
}
- successfulProviderCount++;
break;
}
@@ -433,12 +474,11 @@ namespace MediaBrowser.Providers.Manager
}
catch (Exception ex)
{
- failedProviderCount++;
+ refreshResult.Failures++;
Logger.ErrorException("Error in {0}", ex, provider.Name);
// If a local provider fails, consider that a failure
- refreshResult.Status = ProviderRefreshStatus.Failure;
refreshResult.ErrorMessage = ex.Message;
if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh)
@@ -456,12 +496,8 @@ namespace MediaBrowser.Providers.Manager
.ConfigureAwait(false);
refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType;
- if (remoteResult.Status != ProviderRefreshStatus.Success)
- {
- refreshResult.Status = remoteResult.Status;
- refreshResult.ErrorMessage = remoteResult.ErrorMessage;
- }
- successfulProviderCount += remoteResult.Successes;
+ refreshResult.ErrorMessage = remoteResult.ErrorMessage;
+ refreshResult.Failures += remoteResult.Failures;
}
if (providers.Any(i => !(i is ICustomMetadataProvider)))
@@ -479,13 +515,7 @@ namespace MediaBrowser.Providers.Manager
}
}
- var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0;
-
- if (item.IsUnidentified != isUnidentified)
- {
- item.IsUnidentified = isUnidentified;
- refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
- }
+ //var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0;
foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
{
@@ -503,7 +533,7 @@ namespace MediaBrowser.Providers.Manager
{
return false;
}
-
+
return true;
}
@@ -535,7 +565,6 @@ namespace MediaBrowser.Providers.Manager
}
catch (Exception ex)
{
- refreshResult.Status = ProviderRefreshStatus.Failure;
refreshResult.ErrorMessage = ex.Message;
Logger.ErrorException("Error in {0}", ex, provider.Name);
}
@@ -571,8 +600,6 @@ namespace MediaBrowser.Providers.Manager
MergeData(result, temp, new List<MetadataFields>(), false, false);
refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
-
- refreshResult.Successes++;
}
else
{
@@ -587,7 +614,6 @@ namespace MediaBrowser.Providers.Manager
catch (Exception ex)
{
refreshResult.Failures++;
- refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors;
refreshResult.ErrorMessage = ex.Message;
Logger.ErrorException("Error in {0}", ex, provider.Name);
}
@@ -609,26 +635,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- private async Task<TIdType> CreateInitialLookupInfo(TItemType item, CancellationToken cancellationToken)
- {
- var info = item.GetLookupInfo();
-
- var hasIdentity = info as IHasIdentities<IItemIdentity>;
- if (hasIdentity != null)
- {
- try
- {
- await hasIdentity.FindIdentities(ProviderManager, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error in identity providers", ex);
- }
- }
-
- return info;
- }
-
private void MergeNewData(TItemType source, TIdType lookupInfo)
{
// Copy new provider id's that may have been obtained
@@ -688,10 +694,8 @@ namespace MediaBrowser.Providers.Manager
public class RefreshResult
{
public ItemUpdateType UpdateType { get; set; }
- public ProviderRefreshStatus Status { get; set; }
public string ErrorMessage { get; set; }
public List<Guid> Providers { get; set; }
- public int Successes { get; set; }
public int Failures { get; set; }
}
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index fe0e4890c..f504c9612 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -20,6 +20,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Manager
{
@@ -283,32 +284,31 @@ namespace MediaBrowser.Providers.Manager
{
var options = GetMetadataOptions(item);
- return GetMetadataProvidersInternal<T>(item, options, false);
+ return GetMetadataProvidersInternal<T>(item, options, false, true);
}
- private IEnumerable<IMetadataProvider<T>> GetMetadataProvidersInternal<T>(IHasMetadata item, MetadataOptions options, bool includeDisabled)
+ private IEnumerable<IMetadataProvider<T>> GetMetadataProvidersInternal<T>(IHasMetadata item, MetadataOptions options, bool includeDisabled, bool checkIsOwnedItem)
where T : IHasMetadata
{
// Avoid implicitly captured closure
var currentOptions = options;
return _metadataProviders.OfType<IMetadataProvider<T>>()
- .Where(i => CanRefresh(i, item, currentOptions, includeDisabled))
+ .Where(i => CanRefresh(i, item, currentOptions, includeDisabled, checkIsOwnedItem))
.OrderBy(i => GetConfiguredOrder(i, options))
.ThenBy(GetDefaultOrder);
}
- public IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>> GetItemIdentityProviders<TLookupInfo, TIdentity>()
+ public IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
where TLookupInfo : ItemLookupInfo
- where TIdentity : IItemIdentity
{
- return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo, TIdentity>>();
+ return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo>>();
}
- public IEnumerable<IItemIdentityConverter<TIdentity>> GetItemIdentityConverters<TIdentity>()
- where TIdentity : IItemIdentity
+ public IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
+ where TLookupInfo : ItemLookupInfo
{
- return _identityConverters.OfType<IItemIdentityConverter<TIdentity>>();
+ return _identityConverters.OfType<IItemIdentityConverter<TLookupInfo>>();
}
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
@@ -318,7 +318,7 @@ namespace MediaBrowser.Providers.Manager
return GetImageProviders(item, options, includeDisabled).OfType<IRemoteImageProvider>();
}
- private bool CanRefresh(IMetadataProvider provider, IHasMetadata item, MetadataOptions options, bool includeDisabled)
+ private bool CanRefresh(IMetadataProvider provider, IHasMetadata item, MetadataOptions options, bool includeDisabled, bool checkIsOwnedItem)
{
if (!includeDisabled)
{
@@ -348,7 +348,7 @@ namespace MediaBrowser.Providers.Manager
}
// If this restriction is ever lifted, movie xml providers will have to be updated to prevent owned items like trailers from reading those files
- if (item.IsOwnedItem)
+ if (checkIsOwnedItem && item.IsOwnedItem)
{
if (provider is ILocalMetadataProvider || provider is IRemoteMetadataProvider)
{
@@ -491,11 +491,10 @@ namespace MediaBrowser.Providers.Manager
// Give it a dummy path just so that it looks like a file system item
var dummy = new T()
{
- Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy")
+ Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"),
+ ParentId = Guid.NewGuid()
};
- dummy.SetParent(new Folder());
-
var options = GetMetadataOptions(dummy);
var summary = new MetadataPluginSummary
@@ -523,7 +522,7 @@ namespace MediaBrowser.Providers.Manager
private void AddMetadataPlugins<T>(List<MetadataPlugin> list, T item, MetadataOptions options)
where T : IHasMetadata
{
- var providers = GetMetadataProvidersInternal<T>(item, options, true).ToList();
+ var providers = GetMetadataProvidersInternal<T>(item, options, true, false).ToList();
// Locals
list.AddRange(providers.Where(i => (i is ILocalMetadataProvider)).Select(i => new MetadataPlugin
@@ -701,7 +700,7 @@ namespace MediaBrowser.Providers.Manager
// Manual edit occurred
// Even if save local is off, save locally anyway if the metadata file already exists
- if (fileSaver == null || !isEnabledFor || !File.Exists(fileSaver.GetSavePath(item)))
+ if (fileSaver == null || !isEnabledFor || !_fileSystem.FileExists(fileSaver.GetSavePath(item)))
{
return false;
}
@@ -729,17 +728,20 @@ 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
{
- Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy")
+ Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"),
+ ParentId = Guid.NewGuid()
};
dummy.SetParent(new Folder());
var options = GetMetadataOptions(dummy);
- var providers = GetMetadataProvidersInternal<TItemType>(dummy, options, searchInfo.IncludeDisabledProviders)
+ var providers = GetMetadataProvidersInternal<TItemType>(dummy, options, searchInfo.IncludeDisabledProviders, false)
.OfType<IRemoteSearchProvider<TLookupType>>();
if (!string.IsNullOrEmpty(searchInfo.SearchProviderName))
@@ -756,17 +758,60 @@ namespace MediaBrowser.Providers.Manager
searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode;
}
+ var resultList = new List<RemoteSearchResult>();
+ var foundProviderIds = new Dictionary<Tuple<string, string>, RemoteSearchResult>();
+ var foundTitleYearStrings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+
foreach (var provider in providers)
{
try
{
var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
- var list = results.ToList();
-
- if (list.Count > 0)
+ foreach (var result in results)
{
- return list.Take(10);
+ var bFound = false;
+
+ // This check prevents duplicate search results by comparing provider ids
+ foreach (var providerId in result.ProviderIds)
+ {
+ var idTuple = new Tuple<string, string>(providerId.Key.ToLower(), providerId.Value.ToLower());
+
+ if (!foundProviderIds.ContainsKey(idTuple))
+ {
+ foundProviderIds.Add(idTuple, result);
+ }
+ else
+ {
+ bFound = true;
+ var existingResult = foundProviderIds[idTuple];
+ if (string.IsNullOrEmpty(existingResult.ImageUrl) && !string.IsNullOrEmpty(result.ImageUrl))
+ {
+ existingResult.ImageUrl = result.ImageUrl;
+ }
+ }
+ }
+
+ // This is a workaround duplicate check for movies, where intersecting provider ids are not always available
+ if (typeof(TItemType) == typeof(Movie) || typeof(TItemType) == typeof(Series))
+ {
+ var titleYearString = string.Format("{0} ({1})", result.Name, result.ProductionYear);
+
+ if (foundTitleYearStrings.Contains(titleYearString))
+ {
+ bFound = true;
+ }
+ else
+ {
+ foundTitleYearStrings.Add(titleYearString);
+ }
+
+ }
+
+ if (!bFound && resultList.Count < maxResults)
+ {
+ resultList.Add(result);
+ }
}
}
catch (Exception ex)
@@ -775,8 +820,7 @@ namespace MediaBrowser.Providers.Manager
}
}
- // Nothing found
- return new List<RemoteSearchResult>();
+ return resultList;
}
private async Task<IEnumerable<RemoteSearchResult>> GetSearchResults<TLookupType>(IRemoteSearchProvider<TLookupType> provider, TLookupType searchInfo,
@@ -880,6 +924,11 @@ namespace MediaBrowser.Providers.Manager
private void StartRefreshTimer()
{
+ if (_disposed)
+ {
+ return;
+ }
+
lock (_refreshTimerLock)
{
if (_refreshTimer == null)
@@ -913,10 +962,10 @@ namespace MediaBrowser.Providers.Manager
return;
}
- var item = libraryManager.GetItemById(refreshItem.Item1);
- if (item != null)
+ try
{
- try
+ var item = libraryManager.GetItemById(refreshItem.Item1);
+ if (item != null)
{
// Try to throttle this a little bit.
await Task.Delay(100).ConfigureAwait(false);
@@ -928,10 +977,10 @@ namespace MediaBrowser.Providers.Manager
await task.ConfigureAwait(false);
}
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing item", ex);
- }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error refreshing item", ex);
}
}
@@ -970,7 +1019,7 @@ namespace MediaBrowser.Providers.Manager
{
var folder = (Folder)child;
- await folder.ValidateChildren(new Progress<double>(), CancellationToken.None).ConfigureAwait(false);
+ await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, true).ConfigureAwait(false);
}
}
}
@@ -1014,6 +1063,7 @@ namespace MediaBrowser.Providers.Manager
public void Dispose()
{
_disposed = true;
+ StopRefreshTimer();
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index fa4840f10..20b2ac6cd 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -227,14 +227,8 @@ namespace MediaBrowser.Providers.Manager
target.DateCreated = source.DateCreated;
}
- var sourceHasLanguageSettings = source as IHasPreferredMetadataLanguage;
- var targetHasLanguageSettings = target as IHasPreferredMetadataLanguage;
-
- if (sourceHasLanguageSettings != null && targetHasLanguageSettings != null)
- {
- targetHasLanguageSettings.PreferredMetadataCountryCode = sourceHasLanguageSettings.PreferredMetadataCountryCode;
- targetHasLanguageSettings.PreferredMetadataLanguage = sourceHasLanguageSettings.PreferredMetadataLanguage;
- }
+ target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode;
+ target.PreferredMetadataLanguage = source.PreferredMetadataLanguage;
var sourceHasDisplayOrder = source as IHasDisplayOrder;
var targetHasDisplayOrder = target as IHasDisplayOrder;
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 1d323e567..731d30d84 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -14,7 +14,6 @@
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -49,13 +48,20 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\BDInfo.dll</HintPath>
</Reference>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="DvdLib, Version=1.0.5167.21152, Culture=neutral, PublicKeyToken=7a2f3f5ec8d93575, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
</Reference>
- <Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
+ <Reference Include="MoreLinq, Version=1.1.18418.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
+ <HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
</Reference>
<Reference Include="policy.2.0.taglib-sharp">
<HintPath>..\packages\taglib.2.1.0.0\lib\policy.2.0.taglib-sharp.dll</HintPath>
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index bd83862a8..8884412d2 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -43,7 +44,7 @@ namespace MediaBrowser.Providers.MediaInfo
var audio = (Audio)item;
// Can't extract if we didn't find a video stream in the file
- if (!audio.HasEmbeddedImage)
+ if (!audio.GetMediaSources(false).Take(1).SelectMany(i => i.MediaStreams).Any(i => i.Type == MediaStreamType.EmbeddedImage))
{
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
@@ -55,7 +56,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var path = GetAudioImagePath(item);
- if (!File.Exists(path))
+ if (!_fileSystem.FileExists(path))
{
var semaphore = GetLock(path);
@@ -65,9 +66,9 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
// Check again in case it was saved while waiting for the lock
- if (!File.Exists(path))
+ if (!_fileSystem.FileExists(path))
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, cancellationToken).ConfigureAwait(false))
{
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index 0d4fc6720..4cf507d15 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -103,9 +103,8 @@ namespace MediaBrowser.Providers.MediaInfo
{
var mediaStreams = mediaInfo.MediaStreams;
- audio.FormatName = mediaInfo.Container;
+ //audio.FormatName = mediaInfo.Container;
audio.TotalBitrate = mediaInfo.Bitrate;
- audio.HasEmbeddedImage = mediaStreams.Any(i => i.Type == MediaStreamType.EmbeddedImage);
audio.RunTimeTicks = mediaInfo.RunTimeTicks;
audio.Size = mediaInfo.Size;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index c05f1b64b..7955191c8 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -23,6 +23,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -148,7 +149,7 @@ namespace MediaBrowser.Providers.MediaInfo
private void FetchShortcutInfo(Video video)
{
- video.ShortcutPath = File.ReadAllText(video.Path);
+ video.ShortcutPath = _fileSystem.ReadAllText(video.Path);
}
public Task<ItemUpdateType> FetchAudioInfo<T>(T item, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 9725d7b06..d2aeead5c 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -28,6 +28,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -190,8 +191,8 @@ namespace MediaBrowser.Providers.MediaInfo
var mediaStreams = mediaInfo.MediaStreams;
video.TotalBitrate = mediaInfo.Bitrate;
- video.FormatName = (mediaInfo.Container ?? string.Empty)
- .Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase);
+ //video.FormatName = (mediaInfo.Container ?? string.Empty)
+ // .Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase);
// For dvd's this may not always be accurate, so don't set the runtime if the item already has one
var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0;
@@ -707,7 +708,7 @@ namespace MediaBrowser.Providers.MediaInfo
// Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size
// Once we reach a file that is at least the minimum, return all subsequent ones
- var allVobs = new DirectoryInfo(root).EnumerateFiles("*", SearchOption.AllDirectories)
+ var allVobs = _fileSystem.GetFiles(root)
.Where(file => string.Equals(file.Extension, ".vob", StringComparison.OrdinalIgnoreCase))
.OrderBy(i => i.FullName)
.ToList();
@@ -733,7 +734,7 @@ namespace MediaBrowser.Providers.MediaInfo
return minSizeVobs.Count == 0 ? vobs.Select(i => i.FullName) : minSizeVobs.Select(i => i.FullName);
}
- _logger.Debug("Could not determine vob file list for {0} using DvdLib. Will scan using file sizes.", video.Path);
+ _logger.Info("Could not determine vob file list for {0} using DvdLib. Will scan using file sizes.", video.Path);
}
var files = allVobs
@@ -776,4 +777,4 @@ namespace MediaBrowser.Providers.MediaInfo
return files.Select(i => i.FullName);
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index ae5f93a2e..30995ebad 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -99,7 +100,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- public static IEnumerable<FileSystemInfo> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
+ public static IEnumerable<FileSystemMetadata> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
{
var containingPath = video.ContainingFolderPath;
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index bcea66662..6b035ed81 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -12,6 +12,8 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -22,14 +24,16 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
- public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger)
+ public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
{
_isoManager = isoManager;
_mediaEncoder = mediaEncoder;
_config = config;
_libraryManager = libraryManager;
_logger = logger;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -77,7 +81,7 @@ namespace MediaBrowser.Providers.MediaInfo
// Can't extract if we didn't find a video stream in the file
if (!video.DefaultVideoStreamIndex.HasValue)
{
- _logger.Debug("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty);
+ _logger.Info("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty);
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
@@ -101,7 +105,7 @@ namespace MediaBrowser.Providers.MediaInfo
? MediaProtocol.Http
: MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames);
+ var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, protocol, isoMount, item.PlayableStreamFileNames);
var stream = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
index f133f74db..50b6d3c22 100644
--- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Movies
{
@@ -66,11 +67,11 @@ namespace MediaBrowser.Providers.Movies
var path = FanartMovieImageProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
- var timestampFileInfo = new FileInfo(timestampFile);
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
// Don't check for updates every single time
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
@@ -79,7 +80,7 @@ namespace MediaBrowser.Providers.Movies
}
// Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
@@ -95,7 +96,7 @@ namespace MediaBrowser.Providers.Movies
var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
progress.Report(100);
}
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index 8d0c5cd54..d2e9b160d 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -19,6 +19,10 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Channels;
using MediaBrowser.Providers.TV;
namespace MediaBrowser.Providers.Movies
@@ -58,6 +62,30 @@ namespace MediaBrowser.Providers.Movies
public bool Supports(IHasImages item)
{
+ //var channelItem = item as IChannelMediaItem;
+
+ //if (channelItem != null)
+ //{
+ // if (channelItem.ContentType == ChannelMediaContentType.Movie)
+ // {
+ // return true;
+ // }
+ // if (channelItem.ContentType == ChannelMediaContentType.MovieExtra)
+ // {
+ // if (channelItem.ExtraType == ExtraType.Trailer)
+ // {
+ // return true;
+ // }
+ // }
+ //}
+
+ // Supports images for tv movies
+ //var tvProgram = item as LiveTvProgram;
+ //if (tvProgram != null && tvProgram.IsMovie)
+ //{
+ // return true;
+ //}
+
return item is Movie || item is BoxSet || item is MusicVideo;
}
@@ -234,7 +262,7 @@ namespace MediaBrowser.Providers.Movies
// Process images
var path = GetFanartJsonPath(id);
- var fileInfo = new FileInfo(path);
+ var fileInfo = _fileSystem.GetFileInfo(path);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
@@ -293,7 +321,7 @@ namespace MediaBrowser.Providers.Movies
var path = GetFanartJsonPath(id);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
try
{
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index f5ee33d6b..3c2d9c82f 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -13,6 +13,8 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Providers.Movies
{
@@ -22,14 +24,16 @@ namespace MediaBrowser.Providers.Movies
private readonly ILogger _logger;
private readonly IJsonSerializer _jsonSerializer;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public GenericMovieDbInfo(ILogger logger, IJsonSerializer jsonSerializer, ILibraryManager libraryManager)
+ public GenericMovieDbInfo(ILogger logger, IJsonSerializer jsonSerializer, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_logger = logger;
_jsonSerializer = jsonSerializer;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
public async Task<MetadataResult<T>> GetMetadata(ItemLookupInfo itemId, CancellationToken cancellationToken)
@@ -83,22 +87,26 @@ namespace MediaBrowser.Providers.Movies
if (string.IsNullOrEmpty(tmdbId))
{
movieInfo = await MovieDbProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false);
- if (movieInfo == null) return item;
-
- tmdbId = movieInfo.id.ToString(_usCulture);
+ if (movieInfo != null)
+ {
+ tmdbId = movieInfo.id.ToString(_usCulture);
- dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
- _jsonSerializer.SerializeToFile(movieInfo, dataFilePath);
+ dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _jsonSerializer.SerializeToFile(movieInfo, dataFilePath);
+ }
}
- await MovieDbProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
+ if (!string.IsNullOrWhiteSpace(tmdbId))
+ {
+ await MovieDbProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
- dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
- movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath);
+ dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
+ movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath);
- ProcessMainInfo(item, preferredCountryCode, movieInfo);
- item.HasMetadata = true;
+ ProcessMainInfo(item, preferredCountryCode, movieInfo);
+ item.HasMetadata = true;
+ }
return item;
}
@@ -255,7 +263,14 @@ namespace MediaBrowser.Providers.Movies
{
foreach (var person in movieData.casts.crew)
{
- resultItem.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = person.department });
+ // Normalize this
+ var type = person.department;
+ if (string.Equals(type, "writing", StringComparison.OrdinalIgnoreCase))
+ {
+ type = PersonType.Writer;
+ }
+
+ resultItem.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = type });
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
index 6e0ff14b9..b6f93392b 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
@@ -71,15 +71,6 @@ namespace MediaBrowser.Providers.Movies
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
{
- if (item is ChannelVideoItem || item is LiveTvProgram)
- {
- // Too many channel items to allow backdrops here
- return new List<ImageType>
- {
- ImageType.Primary
- };
- }
-
return new List<ImageType>
{
ImageType.Primary,
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index 48b7140f8..a91714d32 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -16,8 +16,11 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Model.Net;
namespace MediaBrowser.Providers.Movies
{
@@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.Movies
public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken)
where T : BaseItem, new()
{
- var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer, _libraryManager);
+ var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer, _libraryManager, _fileSystem);
return movieDb.GetMetadata(id, cancellationToken);
}
@@ -210,7 +213,7 @@ namespace MediaBrowser.Providers.Movies
var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_jsonSerializer.SerializeToFile(mainResult, dataFilePath);
}
@@ -308,25 +311,38 @@ namespace MediaBrowser.Providers.Movies
var cacheMode = isTmdbId ? CacheMode.None : CacheMode.Unconditional;
var cacheLength = TimeSpan.FromDays(3);
- using (var json = await GetMovieDbResponse(new HttpRequestOptions
+ try
{
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader,
- CacheMode = cacheMode,
- CacheLength = cacheLength
+ using (var json = await GetMovieDbResponse(new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = cancellationToken,
+ AcceptHeader = AcceptHeader,
+ CacheMode = cacheMode,
+ CacheLength = cacheLength
- }).ConfigureAwait(false))
+ }).ConfigureAwait(false))
+ {
+ mainResult = _jsonSerializer.DeserializeFromStream<CompleteMovieData>(json);
+ }
+ }
+ catch (HttpException ex)
{
- mainResult = _jsonSerializer.DeserializeFromStream<CompleteMovieData>(json);
+ // Return null so that callers know there is no metadata for this id
+ if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
+ {
+ return null;
+ }
+
+ throw;
}
cancellationToken.ThrowIfCancellationRequested();
// If the language preference isn't english, then have the overview fallback to english if it's blank
if (mainResult != null &&
- string.IsNullOrEmpty(mainResult.overview) &&
- !string.IsNullOrEmpty(language) &&
+ string.IsNullOrEmpty(mainResult.overview) &&
+ !string.IsNullOrEmpty(language) &&
!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
{
_logger.Info("MovieDbProvider couldn't find meta for language " + language + ". Trying English...");
@@ -352,14 +368,27 @@ namespace MediaBrowser.Providers.Movies
return mainResult;
}
+ private static long _lastRequestTicks;
+
/// <summary>
/// Gets the movie db response.
/// </summary>
- internal Task<Stream> GetMovieDbResponse(HttpRequestOptions options)
+ internal async Task<Stream> GetMovieDbResponse(HttpRequestOptions options)
{
+ var requestIntervalMs = 250;
+ var delayTicks = (requestIntervalMs * 10000) - (DateTime.UtcNow.Ticks - _lastRequestTicks);
+ var delayMs = Math.Min(delayTicks / 10000, requestIntervalMs);
+
+ if (delayMs > 0)
+ {
+ _logger.Debug("Throttling Tmdb by {0} ms", delayMs);
+ await Task.Delay(Convert.ToInt32(delayMs)).ConfigureAwait(false);
+ }
+
options.ResourcePool = MovieDbResourcePool;
+ _lastRequestTicks = DateTime.UtcNow.Ticks;
- return _httpClient.Get(options);
+ return await _httpClient.Get(options).ConfigureAwait(false);
}
public TheMovieDbOptions GetTheMovieDbOptions()
@@ -381,7 +410,7 @@ namespace MediaBrowser.Providers.Movies
// Process images
var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
- var fileInfo = new FileInfo(dataFilePath);
+ var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
index 6fb795411..e8eeab9c5 100644
--- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
@@ -125,6 +125,18 @@ namespace MediaBrowser.Providers.Movies
private async Task<List<RemoteSearchResult>> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
{
+ switch (type)
+ {
+ case "tv":
+ return await GetSearchResultsTv(name, year, language, baseImageUrl, cancellationToken);
+ default:
+ return await GetSearchResultsGeneric(name, type, year, language, baseImageUrl, cancellationToken);
+ }
+ }
+
+ private async Task<List<RemoteSearchResult>> GetSearchResultsGeneric(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
+ {
+
var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type);
using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
@@ -153,7 +165,7 @@ namespace MediaBrowser.Providers.Movies
Name = i.title ?? i.name ?? i.original_title,
ImageUrl = string.IsNullOrWhiteSpace(i.poster_path) ? null : baseImageUrl + i.poster_path
};
-
+
if (!string.IsNullOrWhiteSpace(i.release_date))
{
DateTime r;
@@ -175,6 +187,58 @@ namespace MediaBrowser.Providers.Movies
}
}
+ private async Task<List<RemoteSearchResult>> GetSearchResultsTv(string name, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
+ {
+ var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, "tv");
+
+ using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
+ {
+ Url = url3,
+ CancellationToken = cancellationToken,
+ AcceptHeader = AcceptHeader
+
+ }).ConfigureAwait(false))
+ {
+ var searchResults = _json.DeserializeFromStream<TmdbTvSearchResults>(json);
+
+ var results = searchResults.results ?? new List<TvResult>();
+
+ var index = 0;
+ var resultTuples = results.Select(result => new Tuple<TvResult, int>(result, index++)).ToList();
+
+ return resultTuples.OrderBy(i => GetSearchResultOrder(i.Item1, year))
+ .ThenBy(i => i.Item2)
+ .Select(i => i.Item1)
+ .Select(i =>
+ {
+ var remoteResult = new RemoteSearchResult
+ {
+ SearchProviderName = MovieDbProvider.Current.Name,
+ Name = i.name ?? i.original_name,
+ ImageUrl = string.IsNullOrWhiteSpace(i.poster_path) ? null : baseImageUrl + i.poster_path
+ };
+
+ if (!string.IsNullOrWhiteSpace(i.first_air_date))
+ {
+ DateTime r;
+
+ // These dates are always in this exact format
+ if (DateTime.TryParseExact(i.first_air_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
+ {
+ remoteResult.PremiereDate = r.ToUniversalTime();
+ remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year;
+ }
+ }
+
+ remoteResult.SetProviderId(MetadataProviders.Tmdb, i.id.ToString(EnUs));
+
+ return remoteResult;
+
+ })
+ .ToList();
+ }
+ }
+
private int GetSearchResultOrder(TmdbMovieSearchResult result, int? year)
{
if (year.HasValue)
@@ -192,6 +256,23 @@ namespace MediaBrowser.Providers.Movies
return int.MaxValue;
}
+ private int GetSearchResultOrder(TvResult result, int? year)
+ {
+ if (year.HasValue)
+ {
+ DateTime r;
+
+ // These dates are always in this exact format
+ if (DateTime.TryParseExact(result.first_air_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
+ {
+ // Allow one year tolernace, preserve order from Tmdb
+ return Math.Abs(r.Year - year.Value);
+ }
+ }
+
+ return int.MaxValue;
+ }
+
/// <summary>
/// Class TmdbMovieSearchResult
/// </summary>
@@ -288,9 +369,9 @@ namespace MediaBrowser.Providers.Movies
public class TvResult
{
public string backdrop_path { get; set; }
+ public string first_air_date { get; set; }
public int id { get; set; }
public string original_name { get; set; }
- public string first_air_date { get; set; }
public string poster_path { get; set; }
public double popularity { get; set; }
public string name { get; set; }
@@ -298,6 +379,33 @@ namespace MediaBrowser.Providers.Movies
public int vote_count { get; set; }
}
+ /// <summary>
+ /// Class TmdbTvSearchResults
+ /// </summary>
+ private class TmdbTvSearchResults
+ {
+ /// <summary>
+ /// Gets or sets the page.
+ /// </summary>
+ /// <value>The page.</value>
+ public int page { get; set; }
+ /// <summary>
+ /// Gets or sets the results.
+ /// </summary>
+ /// <value>The results.</value>
+ public List<TvResult> results { get; set; }
+ /// <summary>
+ /// Gets or sets the total_pages.
+ /// </summary>
+ /// <value>The total_pages.</value>
+ public int total_pages { get; set; }
+ /// <summary>
+ /// Gets or sets the total_results.
+ /// </summary>
+ /// <value>The total_results.</value>
+ public int total_results { get; set; }
+ }
+
public class ExternalIdLookupResult
{
public List<object> movie_results { get; set; }
diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
index e96e89a78..8757bdd0d 100644
--- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs
+++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Movies
{
diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
index cc2142292..278d728de 100644
--- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
+++ b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Movies
{
@@ -76,11 +77,11 @@ namespace MediaBrowser.Providers.Movies
var path = MovieDbProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
- var timestampFileInfo = new FileInfo(timestampFile);
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
// Don't check for updates every single time
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 7)
@@ -89,7 +90,7 @@ namespace MediaBrowser.Providers.Movies
}
// Find out the last time we queried tvdb for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
@@ -117,7 +118,7 @@ namespace MediaBrowser.Providers.Movies
}
}
- File.WriteAllText(timestampFile, DateTime.UtcNow.Ticks.ToString(UsCulture), Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, DateTime.UtcNow.Ticks.ToString(UsCulture), Encoding.UTF8);
progress.Report(100);
}
diff --git a/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs b/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
index 2ba700b09..7abe9cc07 100644
--- a/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
+++ b/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
@@ -22,13 +22,15 @@ namespace MediaBrowser.Providers.Music
var image = album.GetRecursiveChildren()
.OfType<Audio>()
- .Select(i => i.GetImagePath(type))
- .FirstOrDefault(i => !string.IsNullOrEmpty(i));
+ .Select(i => i.GetImageInfo(type, 0))
+ .FirstOrDefault(i => i != null && i.IsLocalFile);
+
+ var imagePath = image == null ? null : image.Path;
return Task.FromResult(new DynamicImageResponse
{
- Path = image,
- HasImage = !string.IsNullOrEmpty(image)
+ Path = imagePath,
+ HasImage = !string.IsNullOrEmpty(imagePath)
});
}
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index 859db37ba..0993e7398 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 0032aac62..9939ab797 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
index 3667d70cf..47c2fb8de 100644
--- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
@@ -14,6 +14,7 @@ using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
@@ -125,7 +126,7 @@ namespace MediaBrowser.Providers.Music
var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var response = await _httpClient.Get(new HttpRequestOptions
{
diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs
index eefa1a2f4..cd4f2d502 100644
--- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs
@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
@@ -121,7 +122,7 @@ namespace MediaBrowser.Providers.Music
}).ConfigureAwait(false))
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var xmlFileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs
index b4d50a173..8e872e403 100644
--- a/MediaBrowser.Providers/Music/AudioMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index 0676d93d1..6c4fa71e2 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -17,6 +17,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
@@ -375,7 +376,7 @@ namespace MediaBrowser.Providers.Music
// Process images
var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId);
- var fileInfo = new FileInfo(artistXmlPath);
+ var fileInfo = _fileSystem.GetFileInfo(artistXmlPath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index 597c5c0bc..72e878366 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -18,6 +18,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
@@ -387,7 +388,7 @@ namespace MediaBrowser.Providers.Music
// Process images
var artistXmlPath = GetArtistXmlPath(_config.CommonApplicationPaths, id);
- var fileInfo = new FileInfo(artistXmlPath);
+ var fileInfo = _fileSystem.GetFileInfo(artistXmlPath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
@@ -433,7 +434,7 @@ namespace MediaBrowser.Providers.Music
var xmlPath = GetArtistXmlPath(_config.ApplicationPaths, musicBrainzId);
- Directory.CreateDirectory(Path.GetDirectoryName(xmlPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(xmlPath));
using (var response = await _httpClient.Get(new HttpRequestOptions
{
diff --git a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
index a9b05c99f..c1a2a3f18 100644
--- a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
@@ -13,6 +13,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using MediaBrowser.Providers.TV;
namespace MediaBrowser.Providers.Music
@@ -65,11 +66,11 @@ namespace MediaBrowser.Providers.Music
var path = FanartArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
- var timestampFileInfo = new FileInfo(timestampFile);
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
// Don't check for updates every single time
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
@@ -78,7 +79,7 @@ namespace MediaBrowser.Providers.Music
}
// Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
@@ -94,7 +95,7 @@ namespace MediaBrowser.Providers.Music
var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
progress.Report(100);
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index 70946db36..978d611a8 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -300,7 +300,7 @@ namespace MediaBrowser.Providers.Music
if (!isSearch)
{
options.CacheMode = CacheMode.Unconditional;
- options.CacheLength = TimeSpan.FromDays(7);
+ options.CacheLength = TimeSpan.FromDays(3);
}
using (var xml = await _httpClient.Get(options).ConfigureAwait(false))
diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
index 0456dbfba..4a1fd2f3e 100644
--- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
+++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Providers.Music
{
diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreImageProvider.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreImageProvider.cs
index 3236567fc..f59f3f6c8 100644
--- a/MediaBrowser.Providers/MusicGenres/MusicGenreImageProvider.cs
+++ b/MediaBrowser.Providers/MusicGenres/MusicGenreImageProvider.cs
@@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.MusicGenres
{
diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
index 107b76609..2f1983d70 100644
--- a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
+++ b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.MusicGenres
{
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index 7f804f9df..3f25f0f93 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -79,8 +79,7 @@ namespace MediaBrowser.Providers.Omdb
public bool Supports(IHasImages item)
{
- // Save the http requests since we know it's not currently supported
- // TODO: Check again periodically
+ // We'll hammer Omdb if we enable this
if (item is Person)
{
return false;
diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
index 36e7697d7..c1ec5061d 100644
--- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
@@ -59,6 +59,8 @@ namespace MediaBrowser.Providers.Omdb
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken)
{
+ bool isSearch = false;
+
var list = new List<RemoteSearchResult>();
var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
@@ -75,7 +77,7 @@ namespace MediaBrowser.Providers.Omdb
name = parsedName.Name;
year = year ?? yearInName;
}
-
+
if (string.IsNullOrWhiteSpace(imdbId))
{
if (year.HasValue)
@@ -83,8 +85,10 @@ namespace MediaBrowser.Providers.Omdb
url += "&y=" + year.Value.ToString(CultureInfo.InvariantCulture);
}
- url += "&t=" + WebUtility.UrlEncode(name);
+ // &s means search and returns a list of results as opposed to t
+ url += "&s=" + WebUtility.UrlEncode(name);
url += "&type=" + type;
+ isSearch = true;
}
else
{
@@ -101,9 +105,26 @@ namespace MediaBrowser.Providers.Omdb
}).ConfigureAwait(false))
{
- var result = _jsonSerializer.DeserializeFromStream<SearchResult>(stream);
+ var resultList = new List<SearchResult>();
- if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase))
+ if (isSearch)
+ {
+ var searchResultList = _jsonSerializer.DeserializeFromStream<SearchResultList>(stream);
+ if (searchResultList != null && searchResultList.Search != null)
+ {
+ resultList.AddRange(searchResultList.Search);
+ }
+ }
+ else
+ {
+ var result = _jsonSerializer.DeserializeFromStream<SearchResult>(stream);
+ if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase))
+ {
+ resultList.Add(result);
+ }
+ }
+
+ foreach (var result in resultList)
{
var item = new RemoteSearchResult();
@@ -112,7 +133,8 @@ namespace MediaBrowser.Providers.Omdb
item.SetProviderId(MetadataProviders.Imdb, result.imdbID);
int parsedYear;
- if (int.TryParse(result.Year, NumberStyles.Any, CultureInfo.InvariantCulture, out parsedYear))
+ if (result.Year.Length > 0
+ && int.TryParse(result.Year.Substring(0, Math.Min(result.Year.Length, 4)), NumberStyles.Any, CultureInfo.InvariantCulture, out parsedYear))
{
item.ProductionYear = parsedYear;
}
@@ -264,5 +286,15 @@ namespace MediaBrowser.Providers.Omdb
public string Type { get; set; }
public string Response { get; set; }
}
+
+ private class SearchResultList
+ {
+ /// <summary>
+ /// Gets or sets the results.
+ /// </summary>
+ /// <value>The results.</value>
+ public List<SearchResult> Search { get; set; }
+ }
+
}
}
diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
index dd4231f3f..095eb4447 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
@@ -17,6 +17,7 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.People
{
@@ -200,7 +201,7 @@ namespace MediaBrowser.Providers.People
}).ConfigureAwait(false))
{
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
using (var fs = _fileSystem.GetFileStream(dataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
diff --git a/MediaBrowser.Providers/People/PersonMetadataService.cs b/MediaBrowser.Providers/People/PersonMetadataService.cs
index 9961ff8dc..88ce38950 100644
--- a/MediaBrowser.Providers/People/PersonMetadataService.cs
+++ b/MediaBrowser.Providers/People/PersonMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.People
{
diff --git a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
index 1c5d7f1b5..05dcafbe7 100644
--- a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Photos
{
diff --git a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
index 22a60ea08..f378c3175 100644
--- a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Photos
{
diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs
index b635d4ead..ef3144958 100644
--- a/MediaBrowser.Providers/Photos/PhotoProvider.cs
+++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs
@@ -31,110 +31,111 @@ namespace MediaBrowser.Providers.Photos
try
{
- var file = File.Create(item.Path);
-
- var image = file as TagLib.Image.File;
-
- var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
-
- if (tag != null)
+ using (var file = TagLib.File.Create(item.Path))
{
- var structure = tag.Structure;
+ var image = file as TagLib.Image.File;
- if (structure != null)
+ var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
+
+ if (tag != null)
{
- var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
+ var structure = tag.Structure;
- if (exif != null)
+ if (structure != null)
{
- var exifStructure = exif.Structure;
+ var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
- if (exifStructure != null)
+ if (exif != null)
{
- var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
+ var exifStructure = exif.Structure;
- if (entry != null)
+ if (exifStructure != null)
{
- double val = entry.Value.Numerator;
- val /= entry.Value.Denominator;
- item.Aperture = val;
- }
-
- entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
-
- if (entry != null)
- {
- double val = entry.Value.Numerator;
- val /= entry.Value.Denominator;
- item.ShutterSpeed = val;
+ var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
+
+ if (entry != null)
+ {
+ double val = entry.Value.Numerator;
+ val /= entry.Value.Denominator;
+ item.Aperture = val;
+ }
+
+ entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
+
+ if (entry != null)
+ {
+ double val = entry.Value.Numerator;
+ val /= entry.Value.Denominator;
+ item.ShutterSpeed = val;
+ }
}
}
}
}
- }
-
- item.CameraMake = image.ImageTag.Make;
- item.CameraModel = image.ImageTag.Model;
- item.Width = image.Properties.PhotoWidth;
- item.Height = image.Properties.PhotoHeight;
+ item.CameraMake = image.ImageTag.Make;
+ item.CameraModel = image.ImageTag.Model;
- var rating = image.ImageTag.Rating;
- if (rating.HasValue)
- {
- item.CommunityRating = rating;
- }
- else
- {
- item.CommunityRating = null;
- }
+ item.Width = image.Properties.PhotoWidth;
+ item.Height = image.Properties.PhotoHeight;
- item.Overview = image.ImageTag.Comment;
+ var rating = image.ImageTag.Rating;
+ if (rating.HasValue)
+ {
+ item.CommunityRating = rating;
+ }
+ else
+ {
+ item.CommunityRating = null;
+ }
- if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
- {
- item.Name = image.ImageTag.Title;
- }
+ item.Overview = image.ImageTag.Comment;
- var dateTaken = image.ImageTag.DateTime;
- if (dateTaken.HasValue)
- {
- item.DateCreated = dateTaken.Value;
- item.PremiereDate = dateTaken.Value;
- item.ProductionYear = dateTaken.Value.Year;
- }
+ if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
+ {
+ item.Name = image.ImageTag.Title;
+ }
- item.Genres = image.ImageTag.Genres.ToList();
- item.Tags = image.ImageTag.Keywords.ToList();
- item.Software = image.ImageTag.Software;
+ var dateTaken = image.ImageTag.DateTime;
+ if (dateTaken.HasValue)
+ {
+ item.DateCreated = dateTaken.Value;
+ item.PremiereDate = dateTaken.Value;
+ item.ProductionYear = dateTaken.Value.Year;
+ }
- if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
- {
- item.Orientation = null;
- }
- else
- {
- Model.Drawing.ImageOrientation orientation;
- if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
+ item.Genres = image.ImageTag.Genres.ToList();
+ item.Tags = image.ImageTag.Keywords.ToList();
+ item.Software = image.ImageTag.Software;
+
+ if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
{
- item.Orientation = orientation;
+ item.Orientation = null;
+ }
+ else
+ {
+ Model.Drawing.ImageOrientation orientation;
+ if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
+ {
+ item.Orientation = orientation;
+ }
}
- }
- item.ExposureTime = image.ImageTag.ExposureTime;
- item.FocalLength = image.ImageTag.FocalLength;
+ item.ExposureTime = image.ImageTag.ExposureTime;
+ item.FocalLength = image.ImageTag.FocalLength;
- item.Latitude = image.ImageTag.Latitude;
- item.Longitude = image.ImageTag.Longitude;
- item.Altitude = image.ImageTag.Altitude;
+ item.Latitude = image.ImageTag.Latitude;
+ item.Longitude = image.ImageTag.Longitude;
+ item.Altitude = image.ImageTag.Altitude;
- if (image.ImageTag.ISOSpeedRatings.HasValue)
- {
- item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
- }
- else
- {
- item.IsoSpeedRating = null;
+ if (image.ImageTag.ISOSpeedRatings.HasValue)
+ {
+ item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
+ }
+ else
+ {
+ item.IsoSpeedRating = null;
+ }
}
}
catch (Exception e)
diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
index af4393d18..30e15808f 100644
--- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
+++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Playlists
{
diff --git a/MediaBrowser.Providers/Studios/StudioMetadataService.cs b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
index 5b273d8ca..feede5dbe 100644
--- a/MediaBrowser.Providers/Studios/StudioMetadataService.cs
+++ b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Studios
{
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index f46c9a906..95b8d9bc8 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Studios
{
diff --git a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
index 54db0d5fa..5e48b79e3 100644
--- a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
+++ b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs
@@ -196,7 +196,7 @@ namespace MediaBrowser.Providers.Subtitles
if (!(loginResponse is MethodResponseLogIn))
{
- throw new UnauthorizedAccessException("Authentication to OpenSubtitles failed.");
+ throw new Exception("Authentication to OpenSubtitles failed.");
}
_lastLogin = DateTime.UtcNow;
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index c449edd07..f0c5cbbd3 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Subtitles
{
@@ -252,7 +253,7 @@ namespace MediaBrowser.Providers.Subtitles
_monitor.ReportFileSystemChangeComplete(path, false);
}
- return _libraryManager.GetItemById(itemId).RefreshMetadata(new MetadataRefreshOptions(new DirectoryService())
+ return _libraryManager.GetItemById(itemId).RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
ImageRefreshMode = ImageRefreshMode.ValidationOnly,
MetadataRefreshMode = MetadataRefreshMode.ValidationOnly
diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
index 426ff4318..0faaaa702 100644
--- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
@@ -10,6 +10,8 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Providers.TV
{
@@ -19,15 +21,17 @@ namespace MediaBrowser.Providers.TV
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public DummySeasonProvider(IServerConfigurationManager config, ILogger logger, ILocalizationManager localization, ILibraryManager libraryManager)
+ public DummySeasonProvider(IServerConfigurationManager config, ILogger logger, ILocalizationManager localization, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_config = config;
_logger = logger;
_localization = localization;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
public async Task Run(Series series, CancellationToken cancellationToken)
@@ -38,7 +42,7 @@ namespace MediaBrowser.Providers.TV
if (hasNewSeasons)
{
- var directoryService = new DirectoryService();
+ var directoryService = new DirectoryService(_fileSystem);
//await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false);
@@ -118,7 +122,7 @@ namespace MediaBrowser.Providers.TV
await series.AddChild(season, cancellationToken).ConfigureAwait(false);
- await season.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken).ConfigureAwait(false);
+ await season.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken).ConfigureAwait(false);
return season;
}
diff --git a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
index 339967eeb..dde7ade74 100644
--- a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
+++ b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
index a5b12dad2..323d81a01 100644
--- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
@@ -18,6 +18,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -248,7 +249,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var imagesFilePath = FanartSeriesProvider.Current.GetFanartJsonPath(tvdbId);
- var fileInfo = new FileInfo(imagesFilePath);
+ var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs
index 64c6488fb..71f02e028 100644
--- a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs
@@ -14,6 +14,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -65,11 +66,11 @@ namespace MediaBrowser.Providers.TV
var path = FanartSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
- var timestampFileInfo = new FileInfo(timestampFile);
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
// Don't check for updates every single time
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)
@@ -78,7 +79,7 @@ namespace MediaBrowser.Providers.TV
}
// Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
@@ -94,7 +95,7 @@ namespace MediaBrowser.Providers.TV
var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
progress.Report(100);
}
diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
index 6af2aa38d..5600c165a 100644
--- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -309,7 +310,7 @@ namespace MediaBrowser.Providers.TV
var path = GetFanartJsonPath(tvdbId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
try
{
@@ -356,7 +357,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var imagesFilePath = GetFanartJsonPath(tvdbId);
- var fileInfo = new FileInfo(imagesFilePath);
+ var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 957345607..7dd4f13e4 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -15,6 +15,8 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Providers.TV
{
@@ -24,15 +26,17 @@ namespace MediaBrowser.Providers.TV
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
+ private readonly IFileSystem _fileSystem;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
+ public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, IFileSystem fileSystem)
{
_logger = logger;
_config = config;
_libraryManager = libraryManager;
_localization = localization;
+ _fileSystem = fileSystem;
}
public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
@@ -119,7 +123,7 @@ namespace MediaBrowser.Providers.TV
{
foreach (var series in group)
{
- var directoryService = new DirectoryService();
+ var directoryService = new DirectoryService(_fileSystem);
await series.RefreshMetadata(new MetadataRefreshOptions(directoryService)
{
@@ -395,7 +399,7 @@ namespace MediaBrowser.Providers.TV
if (season == null)
{
- var provider = new DummySeasonProvider(_config, _logger, _localization, _libraryManager);
+ var provider = new DummySeasonProvider(_config, _logger, _localization, _libraryManager, _fileSystem);
season = await provider.AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
}
@@ -413,7 +417,7 @@ namespace MediaBrowser.Providers.TV
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
- await episode.RefreshMetadata(new MetadataRefreshOptions
+ await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
}, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
index ff5e6025d..115eadb96 100644
--- a/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/MovieDbEpisodeImageProvider.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -206,7 +207,7 @@ namespace MediaBrowser.Providers.TV
var dataFilePath = GetDataFilePath(id, seasonNumber, episodeNumber, preferredMetadataLanguage);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_jsonSerializer.SerializeToFile(mainResult, dataFilePath);
}
diff --git a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
index 44c36af8f..693390192 100644
--- a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs
@@ -18,6 +18,7 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -190,7 +191,7 @@ namespace MediaBrowser.Providers.TV
var dataFilePath = GetDataFilePath(id, seasonNumber, preferredMetadataLanguage);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_jsonSerializer.SerializeToFile(mainResult, dataFilePath);
}
diff --git a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs
index f861ad553..994343ee2 100644
--- a/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs
@@ -19,6 +19,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -194,7 +195,7 @@ namespace MediaBrowser.Providers.TV
tmdbId = seriesInfo.id.ToString(_usCulture);
dataFilePath = GetDataFilePath(tmdbId, language);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
@@ -289,7 +290,7 @@ namespace MediaBrowser.Providers.TV
var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage);
- Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
_jsonSerializer.SerializeToFile(mainResult, dataFilePath);
}
@@ -412,7 +413,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
- var fileInfo = new FileInfo(dataFilePath);
+ var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
index 800960c09..22cc19f0c 100644
--- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index 0b2aaa5a0..453f106ae 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -11,6 +11,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -29,7 +30,7 @@ namespace MediaBrowser.Providers.TV
if (refreshOptions.IsPostRecursiveRefresh)
{
- var provider = new DummySeasonProvider(ServerConfigurationManager, Logger, _localization, LibraryManager);
+ var provider = new DummySeasonProvider(ServerConfigurationManager, Logger, _localization, LibraryManager, FileSystem);
try
{
@@ -62,11 +63,6 @@ namespace MediaBrowser.Providers.TV
var sourceItem = source.Item;
var targetItem = target.Item;
- if (replaceData || targetItem.SeasonCount == 0)
- {
- targetItem.SeasonCount = sourceItem.SeasonCount;
- }
-
if (replaceData || string.IsNullOrEmpty(targetItem.AirTime))
{
targetItem.AirTime = sourceItem.AirTime;
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
index 874b5c92d..003665f1c 100644
--- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -10,6 +10,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Providers.TV
{
@@ -27,13 +29,15 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
+ private readonly IFileSystem _fileSystem;
- public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization)
+ public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_logger = logger;
_config = config;
_localization = localization;
+ _fileSystem = fileSystem;
}
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
@@ -50,7 +54,7 @@ namespace MediaBrowser.Providers.TV
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
- await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
+ await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
var numComplete = 0;
@@ -65,12 +69,6 @@ namespace MediaBrowser.Providers.TV
var physicalEpisodes = episodes.Where(i => i.LocationType != LocationType.Virtual)
.ToList();
- series.SeasonCount = episodes
- .Select(i => i.ParentIndexNumber ?? 0)
- .Where(i => i != 0)
- .Distinct()
- .Count();
-
series.SpecialFeatureIds = physicalEpisodes
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
.Select(i => i.Id)
diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
index 969a76e38..10ceba94c 100644
--- a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
@@ -16,6 +16,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -75,7 +76,7 @@ namespace MediaBrowser.Providers.TV
return Task.FromResult<IEnumerable<RemoteImageInfo>>(new RemoteImageInfo[] { });
}
- private RemoteImageInfo GetImageInfo(FileInfo xmlFile, CancellationToken cancellationToken)
+ private RemoteImageInfo GetImageInfo(FileSystemMetadata xmlFile, CancellationToken cancellationToken)
{
var height = 225;
var width = 400;
diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
index 1702a5044..42cf49349 100644
--- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
@@ -17,6 +17,7 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -24,8 +25,11 @@ namespace MediaBrowser.Providers.TV
/// <summary>
/// Class RemoteEpisodeProvider
/// </summary>
- class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo, EpisodeIdentity>, IHasChangeMonitor
+ class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasChangeMonitor
{
+ private const string FullIdFormat = "{0}:{1}:{2}"; // seriesId:seasonIndex:episodeNumbers
+ private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
+
internal static TvdbEpisodeProvider Current;
private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _config;
@@ -43,16 +47,27 @@ namespace MediaBrowser.Providers.TV
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
+ var seriesProviderIds = searchInfo.SeriesProviderIds;
+
var list = new List<RemoteSearchResult>();
- var identity = searchInfo.Identities.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString()) ?? await FindIdentity(searchInfo).ConfigureAwait(false);
+ var identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
+
+ if (identity == null)
+ {
+ await Identify(searchInfo).ConfigureAwait(false);
+ identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
+ }
if (identity != null)
{
- await TvdbSeriesProvider.Current.EnsureSeriesInfo(identity.SeriesId, searchInfo.MetadataLanguage,
- cancellationToken).ConfigureAwait(false);
+ seriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ seriesProviderIds[MetadataProviders.Tvdb.ToString()] = identity.Value.SeriesId;
+ }
- var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
+ if (TvdbSeriesProvider.IsValidSeries(seriesProviderIds))
+ {
+ var seriesDataPath = await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesProviderIds, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
try
{
@@ -95,17 +110,23 @@ namespace MediaBrowser.Providers.TV
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
- var identity = searchInfo.Identities.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString()) ?? await FindIdentity(searchInfo).ConfigureAwait(false);
+ var identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
+
+ if (identity == null)
+ {
+ await Identify(searchInfo).ConfigureAwait(false);
+ identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
+ }
var result = new MetadataResult<Episode>();
if (identity != null)
{
- var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
+ var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.Value.SeriesId);
try
{
- result = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
+ result = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -158,9 +179,9 @@ namespace MediaBrowser.Providers.TV
/// <param name="endingEpisodeNumber">The ending episode number.</param>
/// <param name="seriesDataPath">The series data path.</param>
/// <returns>List{FileInfo}.</returns>
- internal List<FileInfo> GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
+ internal List<FileSystemMetadata> GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
{
- var files = new List<FileInfo>();
+ var files = new List<FileSystemMetadata>();
if (episodeNumber == null)
{
@@ -174,7 +195,7 @@ namespace MediaBrowser.Providers.TV
var file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
- var fileInfo = new FileInfo(file);
+ var fileInfo = _fileSystem.GetFileInfo(file);
var usingAbsoluteData = false;
if (fileInfo.Exists)
@@ -184,7 +205,7 @@ namespace MediaBrowser.Providers.TV
else
{
file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", episodeNumber));
- fileInfo = new FileInfo(file);
+ fileInfo = _fileSystem.GetFileInfo(file);
if (fileInfo.Exists)
{
files.Add(fileInfo);
@@ -206,7 +227,7 @@ namespace MediaBrowser.Providers.TV
file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
}
- fileInfo = new FileInfo(file);
+ fileInfo = _fileSystem.GetFileInfo(file);
if (fileInfo.Exists)
{
files.Add(fileInfo);
@@ -231,11 +252,11 @@ namespace MediaBrowser.Providers.TV
/// <param name="seriesProviderIds">The series provider ids.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
- private MetadataResult<Episode> FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
+ private MetadataResult<Episode> FetchEpisodeData(EpisodeInfo id, Identity? identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
{
- var episodeNumber = identity.IndexNumber;
+ var episodeNumber = identity.HasValue ? (identity.Value.EpisodeNumber) : id.IndexNumber.Value;
var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(seriesProviderIds) ?? 0;
- var seasonNumber = identity.SeasonIndex + seasonOffset;
+ var seasonNumber = identity.HasValue ? (identity.Value.SeasonIndex + seasonOffset) : id.ParentIndexNumber;
string file;
var usingAbsoluteData = false;
@@ -278,7 +299,7 @@ namespace MediaBrowser.Providers.TV
usingAbsoluteData = true;
}
- var end = identity.IndexNumberEnd ?? episodeNumber;
+ var end = identity.HasValue ? (identity.Value.EpisodeNumberEnd ?? episodeNumber) : (id.IndexNumberEnd ?? episodeNumber);
episodeNumber++;
while (episodeNumber <= end)
@@ -753,28 +774,86 @@ namespace MediaBrowser.Providers.TV
});
}
- public Task<EpisodeIdentity> FindIdentity(EpisodeInfo info)
+ public Task Identify(EpisodeInfo info)
{
+ if (info.ProviderIds.ContainsKey(FullIdKey))
+ {
+ return Task.FromResult<object>(null);
+ }
+
string seriesTvdbId;
info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);
if (string.IsNullOrEmpty(seriesTvdbId) || info.IndexNumber == null)
{
- return Task.FromResult<EpisodeIdentity>(null);
+ return Task.FromResult<object>(null);
}
-
- var id = new EpisodeIdentity
- {
- Type = MetadataProviders.Tvdb.ToString(),
- SeriesId = seriesTvdbId,
- SeasonIndex = info.ParentIndexNumber,
- IndexNumber = info.IndexNumber.Value,
- IndexNumberEnd = info.IndexNumberEnd
- };
+
+ var id = new Identity(seriesTvdbId, info.ParentIndexNumber, info.IndexNumber.Value, info.IndexNumberEnd);
+ info.SetProviderId(FullIdKey, id.ToString());
return Task.FromResult(id);
}
public int Order { get { return 0; } }
+
+ public struct Identity
+ {
+ public string SeriesId { get; private set; }
+ public int? SeasonIndex { get; private set; }
+ public int EpisodeNumber { get; private set; }
+ public int? EpisodeNumberEnd { get; private set; }
+
+ public Identity(string id)
+ : this()
+ {
+ this = ParseIdentity(id).Value;
+ }
+
+ public Identity(string seriesId, int? seasonIndex, int episodeNumber, int? episodeNumberEnd)
+ : this()
+ {
+ SeriesId = seriesId;
+ SeasonIndex = seasonIndex;
+ EpisodeNumber = episodeNumber;
+ EpisodeNumberEnd = episodeNumberEnd;
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}:{1}:{2}",
+ SeriesId,
+ SeasonIndex != null ? SeasonIndex.Value.ToString() : "A",
+ EpisodeNumber + (EpisodeNumberEnd != null ? "-" + EpisodeNumberEnd.Value.ToString() : ""));
+ }
+
+ public static Identity? ParseIdentity(string id)
+ {
+ if (string.IsNullOrEmpty(id))
+ return null;
+
+ try {
+ var parts = id.Split(':');
+ var series = parts[0];
+ var season = parts[1] != "A" ? (int?)int.Parse(parts[1]) : null;
+
+ int index;
+ int? indexEnd;
+
+ if (parts[2].Contains("-")) {
+ var split = parts[2].IndexOf("-", StringComparison.OrdinalIgnoreCase);
+ index = int.Parse(parts[2].Substring(0, split));
+ indexEnd = int.Parse(parts[2].Substring(split + 1));
+ } else {
+ index = int.Parse(parts[2]);
+ indexEnd = null;
+ }
+
+ return new Identity(series, season, index, indexEnd);
+ } catch {
+ return null;
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Providers/TV/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TvdbPrescanTask.cs
index 4bc4a2c8d..6ebbb7c39 100644
--- a/MediaBrowser.Providers/TV/TvdbPrescanTask.cs
+++ b/MediaBrowser.Providers/TV/TvdbPrescanTask.cs
@@ -15,6 +15,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -89,11 +90,11 @@ namespace MediaBrowser.Providers.TV
var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var timestampFile = Path.Combine(path, "time.txt");
- var timestampFileInfo = new FileInfo(timestampFile);
+ var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
// Don't check for tvdb updates anymore frequently than 24 hours
if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
@@ -102,7 +103,7 @@ namespace MediaBrowser.Providers.TV
}
// Find out the last time we queried tvdb for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
+ var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
string newUpdateTime;
@@ -157,7 +158,7 @@ namespace MediaBrowser.Providers.TV
await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false);
}
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
+ _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
progress.Report(100);
}
@@ -357,7 +358,7 @@ namespace MediaBrowser.Providers.TV
seriesDataPath = Path.Combine(seriesDataPath, id);
- Directory.CreateDirectory(seriesDataPath);
+ _fileSystem.CreateDirectory(seriesDataPath);
return TvdbSeriesProvider.Current.DownloadSeriesZip(id, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, cancellationToken);
}
diff --git a/MediaBrowser.Providers/TV/TvdbSeasonIdentityProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonIdentityProvider.cs
index 5876c9998..edeea36e4 100644
--- a/MediaBrowser.Providers/TV/TvdbSeasonIdentityProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeasonIdentityProvider.cs
@@ -4,26 +4,57 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeasonIdentityProvider : IItemIdentityProvider<SeasonInfo, SeasonIdentity>
+ public class TvdbSeasonIdentityProvider : IItemIdentityProvider<SeasonInfo>
{
- public Task<SeasonIdentity> FindIdentity(SeasonInfo info)
+ public static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
+
+ public Task Identify(SeasonInfo info)
{
string tvdbSeriesId;
if (!info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbSeriesId) || string.IsNullOrEmpty(tvdbSeriesId) || info.IndexNumber == null)
{
- return Task.FromResult<SeasonIdentity>(null);
+ return Task.FromResult<object>(null);
+ }
+
+ if (string.IsNullOrEmpty(info.GetProviderId(FullIdKey)))
+ {
+ var id = string.Format("{0}:{1}", tvdbSeriesId, info.IndexNumber.Value);
+ info.SetProviderId(FullIdKey, id);
}
+
+ return Task.FromResult<object>(null);
+ }
- var result = new SeasonIdentity
+ public static TvdbSeasonIdentity? ParseIdentity(string id)
+ {
+ try
+ {
+ var parts = id.Split(':');
+ return new TvdbSeasonIdentity(parts[0], int.Parse(parts[1]));
+ }
+ catch
{
- Type = MetadataProviders.Tvdb.ToString(),
- SeriesId = tvdbSeriesId,
- SeasonIndex = info.IndexNumber.Value
- };
+ return null;
+ }
+ }
+ }
+
+ public struct TvdbSeasonIdentity
+ {
+ public string SeriesId { get; private set; }
+ public int Index { get; private set; }
- return Task.FromResult(result);
+ public TvdbSeasonIdentity(string id)
+ : this()
+ {
+ this = TvdbSeasonIdentityProvider.ParseIdentity(id).Value;
}
- public int Order { get { return 0; } }
+ public TvdbSeasonIdentity(string seriesId, int index)
+ : this()
+ {
+ SeriesId = seriesId;
+ Index = index;
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
index 4dbf05d53..d88b39e10 100644
--- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
@@ -17,6 +17,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -65,27 +66,30 @@ namespace MediaBrowser.Providers.TV
var season = (Season)item;
var series = season.Series;
- var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue)
+ if (series != null && season.IndexNumber.HasValue && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
{
- await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);
-
- // Process images
- var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
-
- var path = Path.Combine(seriesDataPath, "banners.xml");
-
- var identity = season.Identities.OfType<SeasonIdentity>()
- .FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString());
-
+ var seriesProviderIds = series.ProviderIds;
var seasonNumber = season.IndexNumber.Value;
+ var identity = TvdbSeasonIdentityProvider.ParseIdentity(season.GetProviderId(TvdbSeasonIdentityProvider.FullIdKey));
+ if (identity == null)
+ {
+ identity = new TvdbSeasonIdentity(series.GetProviderId(MetadataProviders.Tvdb), seasonNumber);
+ }
+
if (identity != null)
{
- seasonNumber = AdjustForSeriesOffset(series, identity.SeasonIndex);
+ var id = identity.Value;
+ seasonNumber = AdjustForSeriesOffset(series, id.Index);
+
+ seriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ seriesProviderIds[MetadataProviders.Tvdb.ToString()] = id.SeriesId;
}
-
+
+ var seriesDataPath = await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesProviderIds, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);
+
+ var path = Path.Combine(seriesDataPath, "banners.xml");
+
try
{
return GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, cancellationToken);
@@ -383,7 +387,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml");
- var fileInfo = new FileInfo(imagesXmlPath);
+ var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
index 6c8a06e38..40b647cee 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
@@ -17,6 +17,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
@@ -61,23 +62,17 @@ namespace MediaBrowser.Providers.TV
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
{
- var series = (Series)item;
- var seriesId = series.GetProviderId(MetadataProviders.Tvdb);
-
- if (!string.IsNullOrEmpty(seriesId))
+ if (TvdbSeriesProvider.IsValidSeries(item.ProviderIds))
{
var language = item.GetPreferredMetadataLanguage();
- await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, language, cancellationToken).ConfigureAwait(false);
-
- // Process images
- var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
+ var seriesDataPath = await TvdbSeriesProvider.Current.EnsureSeriesInfo(item.ProviderIds, language, cancellationToken).ConfigureAwait(false);
var path = Path.Combine(seriesDataPath, "banners.xml");
try
{
- var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
+ var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(item.ProviderIds);
if (seriesOffset != null && seriesOffset.Value != 0)
return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, cancellationToken);
@@ -352,7 +347,7 @@ namespace MediaBrowser.Providers.TV
// Process images
var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml");
- var fileInfo = new FileInfo(imagesXmlPath);
+ var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > (status.DateLastMetadataRefresh ?? DateTime.MinValue);
}
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
index 3298fbc76..24ac7fca6 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
@@ -22,10 +22,11 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Providers.TV
{
- public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IItemIdentityProvider<SeriesInfo, SeriesIdentity>, IHasOrder
+ public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IItemIdentityProvider<SeriesInfo>, IHasOrder
{
private const string TvdbSeriesOffset = "TvdbSeriesOffset";
private const string TvdbSeriesOffsetFormat = "{0}-{1}";
@@ -58,70 +59,48 @@ namespace MediaBrowser.Providers.TV
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
{
- var seriesId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
-
- if (string.IsNullOrWhiteSpace(seriesId))
+ if (IsValidSeries(searchInfo.ProviderIds))
{
- return await FindSeries(searchInfo.Name, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
- }
-
- var metadata = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
+ var metadata = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
- var list = new List<RemoteSearchResult>();
-
- if (metadata.HasMetadata)
- {
- var res = new RemoteSearchResult
+ if (metadata.HasMetadata)
{
- Name = metadata.Item.Name,
- PremiereDate = metadata.Item.PremiereDate,
- ProductionYear = metadata.Item.ProductionYear,
- ProviderIds = metadata.Item.ProviderIds,
- SearchProviderName = Name
- };
-
- list.Add(res);
+ return new List<RemoteSearchResult>
+ {
+ new RemoteSearchResult
+ {
+ Name = metadata.Item.Name,
+ PremiereDate = metadata.Item.PremiereDate,
+ ProductionYear = metadata.Item.ProductionYear,
+ ProviderIds = metadata.Item.ProviderIds,
+ SearchProviderName = Name
+ }
+ };
+ }
}
- return list;
+ return await FindSeries(searchInfo.Name, searchInfo.Year, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
}
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken)
{
var result = new MetadataResult<Series>();
- var seriesId = itemId.GetProviderId(MetadataProviders.Tvdb);
-
- if (string.IsNullOrWhiteSpace(seriesId))
+ if (!IsValidSeries(itemId.ProviderIds))
{
- seriesId = itemId.Identities
- .Where(id => id.Type == MetadataProviders.Tvdb.ToString())
- .Select(id => id.Id)
- .FirstOrDefault();
-
- if (string.IsNullOrWhiteSpace(seriesId))
- {
- var srch = await GetSearchResults(itemId, cancellationToken).ConfigureAwait(false);
-
- var entry = srch.FirstOrDefault();
-
- if (entry != null)
- {
- seriesId = entry.GetProviderId(MetadataProviders.Tvdb);
- }
- }
+ await Identify(itemId).ConfigureAwait(false);
}
cancellationToken.ThrowIfCancellationRequested();
- if (!string.IsNullOrWhiteSpace(seriesId))
+ if (IsValidSeries(itemId.ProviderIds))
{
- await EnsureSeriesInfo(seriesId, itemId.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+ await EnsureSeriesInfo(itemId.ProviderIds, itemId.MetadataLanguage, cancellationToken).ConfigureAwait(false);
result.Item = new Series();
result.HasMetadata = true;
- FetchSeriesData(result, seriesId, cancellationToken);
+ FetchSeriesData(result, itemId.GetProviderId(MetadataProviders.Tvdb), cancellationToken);
await FindAnimeSeriesIndex(result.Item, itemId).ConfigureAwait(false);
}
@@ -181,7 +160,7 @@ namespace MediaBrowser.Providers.TV
cancellationToken.ThrowIfCancellationRequested();
result.ResetPeople();
-
+
FetchActors(result, actorsXmlPath);
}
@@ -252,7 +231,7 @@ namespace MediaBrowser.Providers.TV
if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase))
{
- File.Copy(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true);
+ _fileSystem.CopyFile(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true);
}
await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false);
@@ -263,62 +242,94 @@ namespace MediaBrowser.Providers.TV
return _config.GetConfiguration<TvdbOptions>("tvdb");
}
- private readonly Task _cachedTask = Task.FromResult(true);
- internal Task EnsureSeriesInfo(string seriesId, string preferredMetadataLanguage, CancellationToken cancellationToken)
+ internal static bool IsValidSeries(Dictionary<string, string> seriesProviderIds)
{
- var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesId);
-
- Directory.CreateDirectory(seriesDataPath);
+ string id;
+ if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out id))
+ {
+ return true;
+ }
+ //if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id))
+ //{
+ // return true;
+ //}
+ return false;
+ }
- var files = new DirectoryInfo(seriesDataPath).EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
- .ToList();
+ internal async Task<string> EnsureSeriesInfo(Dictionary<string,string> seriesProviderIds, string preferredMetadataLanguage, CancellationToken cancellationToken)
+ {
+ string seriesId;
+ if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesId))
+ {
+ var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesId);
- var seriesXmlFilename = preferredMetadataLanguage + ".xml";
+ // Only download if not already there
+ // The post-scan task will take care of updates so we don't need to re-download here
+ if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage))
+ {
+ await DownloadSeriesZip(seriesId, seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
+ }
- var download = false;
- var automaticUpdatesEnabled = GetTvDbOptions().EnableAutomaticUpdates;
+ return seriesDataPath;
+ }
- const int cacheDays = 2;
+ return null;
+ }
- var seriesFile = files.FirstOrDefault(i => string.Equals(seriesXmlFilename, i.Name, StringComparison.OrdinalIgnoreCase));
- // No need to check age if automatic updates are enabled
- if (seriesFile == null || !seriesFile.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays))
+ private bool IsCacheValid(string seriesDataPath, string preferredMetadataLanguage)
+ {
+ try
{
- download = true;
- }
+ var files = _fileSystem.GetFiles(seriesDataPath)
+ .ToList();
- var actorsXml = files.FirstOrDefault(i => string.Equals("actors.xml", i.Name, StringComparison.OrdinalIgnoreCase));
- // No need to check age if automatic updates are enabled
- if (actorsXml == null || !actorsXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays))
- {
- download = true;
- }
+ var seriesXmlFilename = preferredMetadataLanguage + ".xml";
+
+ var automaticUpdatesEnabled = GetTvDbOptions().EnableAutomaticUpdates;
+
+ const int cacheDays = 2;
+
+ var seriesFile = files.FirstOrDefault(i => string.Equals(seriesXmlFilename, i.Name, StringComparison.OrdinalIgnoreCase));
+ // No need to check age if automatic updates are enabled
+ if (seriesFile == null || !seriesFile.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays))
+ {
+ return false;
+ }
+
+ var actorsXml = files.FirstOrDefault(i => string.Equals("actors.xml", i.Name, StringComparison.OrdinalIgnoreCase));
+ // No need to check age if automatic updates are enabled
+ if (actorsXml == null || !actorsXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays))
+ {
+ return false;
+ }
- var bannersXml = files.FirstOrDefault(i => string.Equals("banners.xml", i.Name, StringComparison.OrdinalIgnoreCase));
- // No need to check age if automatic updates are enabled
- if (bannersXml == null || !bannersXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays))
+ var bannersXml = files.FirstOrDefault(i => string.Equals("banners.xml", i.Name, StringComparison.OrdinalIgnoreCase));
+ // No need to check age if automatic updates are enabled
+ if (bannersXml == null || !bannersXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays))
+ {
+ return false;
+ }
+ return true;
+ }
+ catch (DirectoryNotFoundException)
{
- download = true;
+ return false;
}
-
- // Only download if not already there
- // The post-scan task will take care of updates so we don't need to re-download here
- if (download)
+ catch (FileNotFoundException)
{
- return DownloadSeriesZip(seriesId, seriesDataPath, null, preferredMetadataLanguage, cancellationToken);
+ return false;
}
-
- return _cachedTask;
}
/// <summary>
/// Finds the series.
/// </summary>
/// <param name="name">The name.</param>
+ /// <param name="year">The year.</param>
/// <param name="language">The language.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.String}.</returns>
- private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, string language, CancellationToken cancellationToken)
+ private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, int? year, string language, CancellationToken cancellationToken)
{
var results = (await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false)).ToList();
@@ -333,7 +344,16 @@ namespace MediaBrowser.Providers.TV
}
}
- return results;
+ return results.Where(i =>
+ {
+ if (year.HasValue && i.ProductionYear.HasValue)
+ {
+ // Allow one year tolerance
+ return Math.Abs(year.Value - i.ProductionYear.Value) <= 1;
+ }
+
+ return true;
+ });
}
private async Task<IEnumerable<RemoteSearchResult>> FindSeriesInternal(string name, string language, CancellationToken cancellationToken)
@@ -402,6 +422,20 @@ namespace MediaBrowser.Providers.TV
}
}
+ var airDateNode = node.SelectSingleNode("./FirstAired");
+ if (airDateNode != null)
+ {
+ var val = airDateNode.InnerText;
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ DateTime date;
+ if (DateTime.TryParse(val, out date))
+ {
+ searchResult.ProductionYear = date.Year;
+ }
+ }
+ }
+
foreach (var title in titles)
{
if (string.Equals(title, comparableName, StringComparison.OrdinalIgnoreCase))
@@ -1107,7 +1141,7 @@ namespace MediaBrowser.Providers.TV
var file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber, episodeNumber));
// Only save the file if not already there, or if the episode has changed
- if (hasEpisodeChanged || !File.Exists(file))
+ if (hasEpisodeChanged || !_fileSystem.FileExists(file))
{
using (var writer = XmlWriter.Create(file, new XmlWriterSettings
{
@@ -1124,7 +1158,7 @@ namespace MediaBrowser.Providers.TV
file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", absoluteNumber));
// Only save the file if not already there, or if the episode has changed
- if (hasEpisodeChanged || !File.Exists(file))
+ if (hasEpisodeChanged || !_fileSystem.FileExists(file))
{
using (var writer = XmlWriter.Create(file, new XmlWriterSettings
{
@@ -1167,11 +1201,10 @@ namespace MediaBrowser.Providers.TV
{
try
{
- foreach (var file in new DirectoryInfo(path)
- .EnumerateFiles("*.xml", SearchOption.AllDirectories)
+ foreach (var file in _fileSystem.GetFilePaths(path, true)
.ToList())
{
- _fileSystem.DeleteFile(file.FullName);
+ _fileSystem.DeleteFile(file);
}
}
catch (DirectoryNotFoundException)
@@ -1240,27 +1273,22 @@ namespace MediaBrowser.Providers.TV
get { return "TheTVDB"; }
}
- public async Task<SeriesIdentity> FindIdentity(SeriesInfo info)
+ public async Task Identify(SeriesInfo info)
{
- string tvdbId;
- if (!info.ProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbId))
+ if (!string.IsNullOrWhiteSpace(info.GetProviderId(MetadataProviders.Tvdb)))
{
- var srch = await GetSearchResults(info, CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
- var entry = srch.FirstOrDefault();
+ var srch = await FindSeries(info.Name, info.Year, info.MetadataLanguage, CancellationToken.None).ConfigureAwait(false);
- if (entry != null)
- {
- tvdbId = entry.GetProviderId(MetadataProviders.Tvdb);
- }
- }
+ var entry = srch.FirstOrDefault();
- if (!string.IsNullOrWhiteSpace(tvdbId))
+ if (entry != null)
{
- return new SeriesIdentity { Type = MetadataProviders.Tvdb.ToString(), Id = tvdbId };
+ var id = entry.GetProviderId(MetadataProviders.Tvdb);
+ info.SetProviderId(MetadataProviders.Tvdb, id);
}
-
- return null;
}
public int Order
diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs
index 84f2b0380..7c74e23f2 100644
--- a/MediaBrowser.Providers/Users/UserMetadataService.cs
+++ b/MediaBrowser.Providers/Users/UserMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Users
{
diff --git a/MediaBrowser.Providers/Videos/VideoMetadataService.cs b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
index 68c36a84c..561ac8323 100644
--- a/MediaBrowser.Providers/Videos/VideoMetadataService.cs
+++ b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Providers.Videos
{
diff --git a/MediaBrowser.Providers/Years/YearMetadataService.cs b/MediaBrowser.Providers/Years/YearMetadataService.cs
index 3e6db7629..131411756 100644
--- a/MediaBrowser.Providers/Years/YearMetadataService.cs
+++ b/MediaBrowser.Providers/Years/YearMetadataService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Providers.Years
{
diff --git a/MediaBrowser.Providers/packages.config b/MediaBrowser.Providers/packages.config
index be21e92dc..9ff08e4f4 100644
--- a/MediaBrowser.Providers/packages.config
+++ b/MediaBrowser.Providers/packages.config
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
- <package id="morelinq" version="1.1.0" targetFramework="net45" />
+ <package id="morelinq" version="1.1.1" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
<package id="taglib" version="2.1.0.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs
deleted file mode 100644
index 042beb7e5..000000000
--- a/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Channels
-{
- public class ChannelItemImageProvider : IDynamicImageProvider, IHasItemChangeMonitor
- {
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
-
- public ChannelItemImageProvider(IHttpClient httpClient, ILogger logger)
- {
- _httpClient = httpClient;
- _logger = logger;
- }
-
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
- {
- return new[] { ImageType.Primary };
- }
-
- public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
- {
- var channelItem = (IChannelItem)item;
-
- var imageResponse = new DynamicImageResponse();
-
- if (!string.IsNullOrEmpty(channelItem.OriginalImageUrl))
- {
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = channelItem.OriginalImageUrl
- };
-
- var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
-
- if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Content;
- imageResponse.SetFormatFromMimeType(response.ContentType);
- }
- else
- {
- _logger.Error("Provider did not return an image content type.");
- }
- }
-
- return imageResponse;
- }
-
- public string Name
- {
- get { return "Channel Image Provider"; }
- }
-
- public bool Supports(IHasImages item)
- {
- return item is IChannelItem;
- }
-
- public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
- {
- var channelItem = item as IChannelItem;
-
- if (channelItem != null)
- {
- return !channelItem.HasImage(ImageType.Primary) && !string.IsNullOrWhiteSpace(channelItem.OriginalImageUrl);
- }
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index f670176e6..ba759dcb9 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -25,13 +25,13 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Channels
{
public class ChannelManager : IChannelManager, IDisposable
{
private IChannel[] _channels;
- private IChannelFactory[] _factories;
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
@@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
+ private readonly IProviderManager _providerManager;
private readonly ILocalizationManager _localization;
private readonly ConcurrentDictionary<Guid, bool> _refreshedItems = new ConcurrentDictionary<Guid, bool>();
@@ -51,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private Timer _refreshTimer;
private Timer _clearDownloadCountsTimer;
- public ChannelManager(IUserManager userManager, IDtoService dtoService, ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IUserDataManager userDataManager, IJsonSerializer jsonSerializer, ILocalizationManager localization, IHttpClient httpClient)
+ public ChannelManager(IUserManager userManager, IDtoService dtoService, ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IUserDataManager userDataManager, IJsonSerializer jsonSerializer, ILocalizationManager localization, IHttpClient httpClient, IProviderManager providerManager)
{
_userManager = userManager;
_dtoService = dtoService;
@@ -63,6 +64,7 @@ namespace MediaBrowser.Server.Implementations.Channels
_jsonSerializer = jsonSerializer;
_localization = localization;
_httpClient = httpClient;
+ _providerManager = providerManager;
_refreshTimer = new Timer(s => _refreshedItems.Clear(), null, TimeSpan.FromHours(3), TimeSpan.FromHours(3));
_clearDownloadCountsTimer = new Timer(s => _downloadCounts.Clear(), null, TimeSpan.FromHours(24), TimeSpan.FromHours(24));
@@ -76,10 +78,9 @@ namespace MediaBrowser.Server.Implementations.Channels
}
}
- public void AddParts(IEnumerable<IChannel> channels, IEnumerable<IChannelFactory> factories)
+ public void AddParts(IEnumerable<IChannel> channels)
{
- _channels = channels.Where(i => !(i is IFactoryChannel)).ToArray();
- _factories = factories.ToArray();
+ _channels = channels.ToArray();
}
public string ChannelDownloadPath
@@ -99,20 +100,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private IEnumerable<IChannel> GetAllChannels()
{
- return _factories
- .SelectMany(i =>
- {
- try
- {
- return i.GetChannels().ToList();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting channel list", ex);
- return new List<IChannel>();
- }
- })
- .Concat(_channels)
+ return _channels
.OrderBy(i => i.Name);
}
@@ -130,8 +118,18 @@ namespace MediaBrowser.Server.Implementations.Channels
if (query.SupportsLatestItems.HasValue)
{
var val = query.SupportsLatestItems.Value;
- channels = channels.Where(i => (GetChannelProvider(i) is ISupportsLatestMedia) == val)
- .ToList();
+ channels = channels.Where(i =>
+ {
+ try
+ {
+ return (GetChannelProvider(i) is ISupportsLatestMedia) == val;
+ }
+ catch
+ {
+ return false;
+ }
+
+ }).ToList();
}
if (query.IsFavorite.HasValue)
{
@@ -142,8 +140,23 @@ namespace MediaBrowser.Server.Implementations.Channels
if (user != null)
{
- channels = channels.Where(i => GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N")) && i.IsVisible(user))
- .ToList();
+ channels = channels.Where(i =>
+ {
+ if (!i.IsVisible(user))
+ {
+ return false;
+ }
+
+ try
+ {
+ return GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N"));
+ }
+ catch
+ {
+ return false;
+ }
+
+ }).ToList();
}
var all = channels;
@@ -203,9 +216,7 @@ namespace MediaBrowser.Server.Implementations.Channels
try
{
- var item = await GetChannel(channelInfo, cancellationToken).ConfigureAwait(false);
-
- _libraryManager.RegisterItem(item);
+ await GetChannel(channelInfo, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -233,8 +244,6 @@ namespace MediaBrowser.Server.Implementations.Channels
if (item == null)
{
item = GetChannel(channel, CancellationToken.None).Result;
-
- _libraryManager.RegisterItem(item);
}
return item;
@@ -318,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.Channels
try
{
- var files = new DirectoryInfo(parentPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly);
+ var files = _fileSystem.GetFiles(parentPath);
if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
@@ -403,18 +412,15 @@ namespace MediaBrowser.Server.Implementations.Channels
var path = Channel.GetInternalMetadataPath(_config.ApplicationPaths.InternalMetadataPath, id);
- var fileInfo = new DirectoryInfo(path);
-
var isNew = false;
- if (!fileInfo.Exists)
+ if (!_fileSystem.DirectoryExists(path))
{
_logger.Debug("Creating directory {0}", path);
- Directory.CreateDirectory(path);
- fileInfo = new DirectoryInfo(path);
+ _fileSystem.CreateDirectory(path);
- if (!fileInfo.Exists)
+ if (!_fileSystem.DirectoryExists(path))
{
throw new IOException("Path not created: " + path);
}
@@ -423,6 +429,7 @@ namespace MediaBrowser.Server.Implementations.Channels
}
var item = _libraryManager.GetItemById(id) as Channel;
+ var channelId = channelInfo.Name.GetMD5().ToString("N");
if (item == null)
{
@@ -430,25 +437,30 @@ namespace MediaBrowser.Server.Implementations.Channels
{
Name = channelInfo.Name,
Id = id,
- DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
- DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
- Path = path
+ DateCreated = _fileSystem.GetCreationTimeUtc(path),
+ DateModified = _fileSystem.GetLastWriteTimeUtc(path),
+ Path = path,
+ ChannelId = channelId
};
isNew = true;
}
+ if (!string.Equals(item.ChannelId, channelId, StringComparison.OrdinalIgnoreCase))
+ {
+ isNew = true;
+ }
+
item.OfficialRating = GetOfficialRating(channelInfo.ParentalRating);
item.Overview = channelInfo.Description;
item.HomePageUrl = channelInfo.HomePageUrl;
- item.OriginalChannelName = channelInfo.Name;
- if (string.IsNullOrEmpty(item.Name))
+ if (string.IsNullOrWhiteSpace(item.Name))
{
item.Name = channelInfo.Name;
}
-
- await item.RefreshMetadata(new MetadataRefreshOptions
+
+ await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew
@@ -481,9 +493,14 @@ namespace MediaBrowser.Server.Implementations.Channels
public IEnumerable<ChannelFeatures> GetAllChannelFeatures()
{
- return GetAllChannels()
- .Select(GetChannelEntity)
- .OrderBy(i => i.SortName)
+ var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Channel).Name },
+ SortBy = new[] { ItemSortBy.SortName }
+
+ }).Items;
+
+ return inputItems
.Select(i => GetChannelFeatures(i.Id.ToString("N")));
}
@@ -660,7 +677,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
internalItems = ApplyFilters(internalItems, query.Filters, user).ToArray();
- await RefreshIfNeeded(internalItems, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+ RefreshIfNeeded(internalItems);
if (query.StartIndex.HasValue)
{
@@ -825,7 +842,7 @@ namespace MediaBrowser.Server.Implementations.Channels
var internalResult = await GetAllMediaInternal(query, cancellationToken).ConfigureAwait(false);
- await RefreshIfNeeded(internalResult.Items, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+ RefreshIfNeeded(internalResult.Items);
var dtoOptions = new DtoOptions();
@@ -965,7 +982,7 @@ namespace MediaBrowser.Server.Implementations.Channels
}
}
- return await GetReturnItems(internalItems, providerTotalRecordCount, user, query, progress, cancellationToken).ConfigureAwait(false);
+ return await GetReturnItems(internalItems, providerTotalRecordCount, user, query).ConfigureAwait(false);
}
public async Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken)
@@ -1082,7 +1099,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
_jsonSerializer.SerializeToFile(result, path);
}
@@ -1134,9 +1151,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private async Task<QueryResult<BaseItem>> GetReturnItems(IEnumerable<BaseItem> items,
int? totalCountFromProvider,
User user,
- ChannelItemQuery query,
- IProgress<double> progress,
- CancellationToken cancellationToken)
+ ChannelItemQuery query)
{
items = ApplyFilters(items, query.Filters, user);
@@ -1159,7 +1174,7 @@ namespace MediaBrowser.Server.Implementations.Channels
}
var returnItemArray = all.ToArray();
- await RefreshIfNeeded(returnItemArray, progress, cancellationToken).ConfigureAwait(false);
+ RefreshIfNeeded(returnItemArray);
return new QueryResult<BaseItem>
{
@@ -1191,7 +1206,7 @@ namespace MediaBrowser.Server.Implementations.Channels
_logger.ErrorException("Error retrieving channel item from database", ex);
}
- if (item == null || !string.Equals(item.DataVersion, channnelDataVersion, StringComparison.Ordinal))
+ if (item == null || !string.Equals(item.ExternalEtag, channnelDataVersion, StringComparison.Ordinal))
{
item = new T();
isNew = true;
@@ -1201,7 +1216,7 @@ namespace MediaBrowser.Server.Implementations.Channels
isNew = false;
}
- item.DataVersion = channnelDataVersion;
+ item.ExternalEtag = channnelDataVersion;
item.Id = id;
return item;
}
@@ -1240,17 +1255,18 @@ namespace MediaBrowser.Server.Implementations.Channels
item.ProviderIds = info.ProviderIds;
item.OfficialRating = info.OfficialRating;
- item.DateCreated = info.DateCreated.HasValue ?
- info.DateCreated.Value :
- DateTime.UtcNow;
+ item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
}
var channelItem = (IChannelItem)item;
- channelItem.OriginalImageUrl = info.ImageUrl;
- channelItem.ExternalId = info.Id;
channelItem.ChannelId = internalChannelId.ToString("N");
- channelItem.ChannelItemType = info.Type;
+
+ if (!string.Equals(channelItem.ExternalId, info.Id, StringComparison.OrdinalIgnoreCase))
+ {
+ isNew = true;
+ }
+ channelItem.ExternalId = info.Id;
if (isNew)
{
@@ -1270,48 +1286,52 @@ namespace MediaBrowser.Server.Implementations.Channels
item.Path = mediaSource == null ? null : mediaSource.Path;
}
+ if (!string.IsNullOrWhiteSpace(info.ImageUrl))
+ {
+ item.SetImagePath(ImageType.Primary, info.ImageUrl);
+ }
+
if (isNew)
{
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
- _libraryManager.RegisterItem(item);
- await _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>()).ConfigureAwait(false);
+ if (info.People != null && info.People.Count > 0)
+ {
+ await _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>()).ConfigureAwait(false);
+ }
}
return item;
}
- private async Task RefreshIfNeeded(BaseItem[] programs, IProgress<double> progress, CancellationToken cancellationToken)
+ private void RefreshIfNeeded(BaseItem[] programs)
{
- var numComplete = 0;
- var numItems = programs.Length;
-
foreach (var program in programs)
{
- await RefreshIfNeeded(program, cancellationToken).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= numItems;
- progress.Report(percent * 100);
+ RefreshIfNeeded(program);
}
}
- private readonly Task _cachedTask = Task.FromResult(true);
- private Task RefreshIfNeeded(BaseItem program, CancellationToken cancellationToken)
+ private void RefreshIfNeeded(BaseItem program)
{
if (!_refreshedItems.ContainsKey(program.Id))
{
_refreshedItems.TryAdd(program.Id, true);
- return program.RefreshMetadata(cancellationToken);
+ _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem));
}
- return _cachedTask;
}
internal IChannel GetChannelProvider(Channel channel)
{
- return GetAllChannels().First(i => string.Equals(i.Name, channel.OriginalChannelName, StringComparison.OrdinalIgnoreCase));
+ var result = GetAllChannels().FirstOrDefault(i => string.Equals(i.Name.GetMD5().ToString("N"), channel.ChannelId, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, channel.Name, StringComparison.OrdinalIgnoreCase));
+
+ if (result == null)
+ {
+ throw new ResourceNotFoundException("No channel provider found for channel " + channel.Name);
+ }
+
+ return result;
}
private IEnumerable<BaseItem> ApplyFilters(IEnumerable<BaseItem> items, IEnumerable<ItemFilter> filters, User user)
@@ -1462,7 +1482,7 @@ namespace MediaBrowser.Server.Implementations.Channels
options.RequestHeaders[header.Key] = header.Value;
}
- Directory.CreateDirectory(Path.GetDirectoryName(destination));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(destination));
// Determine output extension
var response = await _httpClient.GetTempFileResponse(options).ConfigureAwait(false);
@@ -1500,7 +1520,7 @@ namespace MediaBrowser.Server.Implementations.Channels
throw new ApplicationException("Unexpected response type encountered: " + response.ContentType);
}
- File.Copy(response.TempFilePath, destination, true);
+ _fileSystem.CopyFile(response.TempFilePath, destination, true);
try
{
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
index 976fa5615..2e9d42f49 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs
@@ -87,6 +87,7 @@ namespace MediaBrowser.Server.Implementations.Channels
const int currentRefreshLevel = 1;
var maxRefreshLevel = features.AutoRefreshLevels ?? 0;
+ maxRefreshLevel = Math.Max(maxRefreshLevel, 2);
if (maxRefreshLevel > 0)
{
@@ -143,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Channels
private async Task CleanChannel(Guid id, CancellationToken cancellationToken)
{
- _logger.Debug("Cleaning channel {0} from database", id);
+ _logger.Info("Cleaning channel {0} from database", id);
// Delete all channel items
var allIds = _libraryManager.GetItemIds(new InternalItemsQuery
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
index f5ddbdb78..9ea457284 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -10,8 +10,10 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Server.Implementations.Photos;
using MoreLinq;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Collections
{
@@ -21,6 +23,17 @@ namespace MediaBrowser.Server.Implementations.Collections
{
}
+ protected override bool Supports(IHasImages item)
+ {
+ // Right now this is the only way to prevent this image from getting created ahead of internet image providers
+ if (!item.IsLocked)
+ {
+ return false;
+ }
+
+ return base.Supports(item);
+ }
+
protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
{
var playlist = (BoxSet)item;
@@ -62,7 +75,27 @@ namespace MediaBrowser.Server.Implementations.Collections
.DistinctBy(i => i.Id)
.ToList();
- return Task.FromResult(GetFinalItems(items));
+ return Task.FromResult(GetFinalItems(items, 2));
+ }
+
+ protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ {
+ var image = itemsWithImages
+ .Where(i => i.HasImage(ImageType.Primary) && i.GetImageInfo(ImageType.Primary, 0).IsLocalFile && Path.HasExtension(i.GetImagePath(ImageType.Primary)))
+ .Select(i => i.GetImagePath(ImageType.Primary))
+ .FirstOrDefault();
+
+ if (string.IsNullOrWhiteSpace(image))
+ {
+ return null;
+ }
+
+ var ext = Path.GetExtension(image);
+
+ var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext);
+ File.Copy(image, outputPath);
+
+ return outputPath;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
index 04f82db6f..5c98e401f 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Collections
{
@@ -21,17 +22,19 @@ namespace MediaBrowser.Server.Implementations.Collections
private readonly IFileSystem _fileSystem;
private readonly ILibraryMonitor _iLibraryMonitor;
private readonly ILogger _logger;
+ private readonly IProviderManager _providerManager;
public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
- public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger)
+ public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger, IProviderManager providerManager)
{
_libraryManager = libraryManager;
_fileSystem = fileSystem;
_iLibraryMonitor = iLibraryMonitor;
_logger = logger;
+ _providerManager = providerManager;
}
public Folder GetCollectionsFolder(string userId)
@@ -70,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.Collections
try
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var collection = new BoxSet
{
@@ -88,12 +91,18 @@ namespace MediaBrowser.Server.Implementations.Collections
await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
- await collection.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService()), CancellationToken.None)
- .ConfigureAwait(false);
-
if (options.ItemIdList.Count > 0)
{
- await AddToCollection(collection.Id, options.ItemIdList, false);
+ await AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(_fileSystem)
+ {
+ // The initial adding of items is going to create a local metadata file
+ // This will cause internet metadata to be skipped as a result
+ MetadataRefreshMode = MetadataRefreshMode.FullRefresh
+ });
+ }
+ else
+ {
+ _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem));
}
EventHelper.FireEventIfNotNull(CollectionCreated, this, new CollectionCreatedEventArgs
@@ -141,10 +150,10 @@ namespace MediaBrowser.Server.Implementations.Collections
public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
{
- return AddToCollection(collectionId, ids, true);
+ return AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(_fileSystem));
}
- private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent)
+ private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
{
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@@ -168,29 +177,31 @@ namespace MediaBrowser.Server.Implementations.Collections
itemList.Add(item);
- if (currentLinkedChildren.Any(i => i.Id == itemId))
+ if (currentLinkedChildren.All(i => i.Id != itemId))
{
- throw new ArgumentException("Item already exists in collection");
+ list.Add(LinkedChild.Create(item));
}
-
- list.Add(LinkedChild.Create(item));
}
- collection.LinkedChildren.AddRange(list);
+ if (list.Count > 0)
+ {
+ collection.LinkedChildren.AddRange(list);
- collection.UpdateRatingToContent();
+ collection.UpdateRatingToContent();
- await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
+ await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- if (fireEvent)
- {
- EventHelper.FireEventIfNotNull(ItemsAddedToCollection, this, new CollectionModifiedEventArgs
+ _providerManager.QueueRefresh(collection.Id, refreshOptions);
+
+ if (fireEvent)
{
- Collection = collection,
- ItemsChanged = itemList
+ EventHelper.FireEventIfNotNull(ItemsAddedToCollection, this, new CollectionModifiedEventArgs
+ {
+ Collection = collection,
+ ItemsChanged = itemList
- }, _logger);
+ }, _logger);
+ }
}
}
@@ -225,8 +236,8 @@ namespace MediaBrowser.Server.Implementations.Collections
}
}
- var shortcutFiles = Directory
- .EnumerateFiles(collection.Path, "*", SearchOption.TopDirectoryOnly)
+ var shortcutFiles = _fileSystem
+ .GetFilePaths(collection.Path)
.Where(i => _fileSystem.IsShortcut(i))
.ToList();
@@ -263,7 +274,7 @@ namespace MediaBrowser.Server.Implementations.Collections
collection.UpdateRatingToContent();
await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
+ _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem));
EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs
{
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
index 915a27c11..85b143a40 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs
@@ -1,23 +1,27 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using System.IO;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Collections
{
public class CollectionsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private IFileSystem _fileSystem;
- public CollectionsDynamicFolder(IApplicationPaths appPaths)
+ public CollectionsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "collections");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new ManualCollectionsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
index bf199503b..a7d3854e7 100644
--- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Model.Serialization;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Configuration
{
@@ -23,14 +24,16 @@ namespace MediaBrowser.Server.Implementations.Configuration
/// </summary>
public class ServerConfigurationManager : BaseConfigurationManager, IServerConfigurationManager
{
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfigurationManager" /> class.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="xmlSerializer">The XML serializer.</param>
- public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer)
- : base(applicationPaths, logManager, xmlSerializer)
+ /// <param name="fileSystem">The file system.</param>
+ public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
+ : base(applicationPaths, logManager, xmlSerializer, fileSystem)
{
UpdateItemsByNamePath();
UpdateMetadataPath();
@@ -198,10 +201,12 @@ namespace MediaBrowser.Server.Implementations.Configuration
&& !string.Equals(Configuration.ItemsByNamePath ?? string.Empty, newPath))
{
// Validate
- if (!Directory.Exists(newPath))
+ if (!FileSystem.DirectoryExists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
+
+ EnsureWriteAccess(newPath);
}
}
@@ -218,10 +223,12 @@ namespace MediaBrowser.Server.Implementations.Configuration
&& !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath))
{
// Validate
- if (!Directory.Exists(newPath))
+ if (!FileSystem.DirectoryExists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
+
+ EnsureWriteAccess(newPath);
}
}
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
index 8a659fb65..9ad04ebbd 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs
@@ -10,6 +10,8 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Connect
{
@@ -23,8 +25,9 @@ namespace MediaBrowser.Server.Implementations.Connect
private readonly INetworkManager _networkManager;
private readonly IApplicationHost _appHost;
+ private readonly IFileSystem _fileSystem;
- public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost)
+ public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem)
{
_httpClient = httpClient;
_appPaths = appPaths;
@@ -32,6 +35,7 @@ namespace MediaBrowser.Server.Implementations.Connect
_networkManager = networkManager;
_connectManager = connectManager;
_appHost = appHost;
+ _fileSystem = fileSystem;
}
public void Run()
@@ -45,14 +49,23 @@ namespace MediaBrowser.Server.Implementations.Connect
private async void TimerCallback(object state)
{
+ var index = 0;
+
foreach (var ipLookupUrl in _ipLookups)
{
try
{
+ // Sometimes whatismyipaddress might fail, but it won't do us any good having users raise alarms over it.
+ var logErrors = index > 0;
+
+#if DEBUG
+ logErrors = true;
+#endif
using (var stream = await _httpClient.Get(new HttpRequestOptions
{
Url = ipLookupUrl,
- UserAgent = "Emby Server/" + _appHost.ApplicationVersion
+ UserAgent = "Emby/" + _appHost.ApplicationVersion,
+ LogErrors = logErrors
}).ConfigureAwait(false))
{
@@ -60,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
var address = await reader.ReadToEndAsync().ConfigureAwait(false);
- if (IsValid(address))
+ if (IsValid(address, ipLookupUrl))
{
((ConnectManager)_connectManager).OnWanAddressResolved(address);
CacheAddress(address);
@@ -76,6 +89,8 @@ namespace MediaBrowser.Server.Implementations.Connect
{
_logger.ErrorException("Error getting connection info", ex);
}
+
+ index++;
}
}
@@ -90,8 +105,8 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
- File.WriteAllText(path, address, Encoding.UTF8);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.WriteAllText(path, address, Encoding.UTF8);
}
catch (Exception ex)
{
@@ -105,9 +120,9 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- var endpoint = File.ReadAllText(path, Encoding.UTF8);
+ var endpoint = _fileSystem.ReadAllText(path, Encoding.UTF8);
- if (IsValid(endpoint))
+ if (IsValid(endpoint, "cache"))
{
((ConnectManager)_connectManager).OnWanAddressResolved(endpoint);
}
@@ -122,14 +137,14 @@ namespace MediaBrowser.Server.Implementations.Connect
}
}
- private bool IsValid(string address)
+ private bool IsValid(string address, string source)
{
IPAddress ipAddress;
var valid = IPAddress.TryParse(address, out ipAddress);
if (!valid)
{
- _logger.Error("{0} is not a valid ip address", address);
+ _logger.Error("{0} is not a valid ip address. Source: {1}", address, source);
}
return valid;
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index 7cd96c5f3..f1de09d56 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -23,6 +23,8 @@ using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Connect
{
@@ -40,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.Connect
private readonly IUserManager _userManager;
private readonly IProviderManager _providerManager;
private readonly ISecurityManager _securityManager;
+ private readonly IFileSystem _fileSystem;
private ConnectData _data = new ConnectData();
@@ -104,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.Connect
IEncryptionManager encryption,
IHttpClient httpClient,
IServerApplicationHost appHost,
- IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager)
+ IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
@@ -116,6 +119,7 @@ namespace MediaBrowser.Server.Implementations.Connect
_userManager = userManager;
_providerManager = providerManager;
_securityManager = securityManager;
+ _fileSystem = fileSystem;
_userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated;
_config.ConfigurationUpdated += _config_ConfigurationUpdated;
@@ -315,7 +319,7 @@ namespace MediaBrowser.Server.Implementations.Connect
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var json = _json.SerializeToString(_data);
@@ -323,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.Connect
lock (_dataFileLock)
{
- File.WriteAllText(path, encrypted, Encoding.UTF8);
+ _fileSystem.WriteAllText(path, encrypted, Encoding.UTF8);
}
}
catch (Exception ex)
@@ -340,7 +344,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
lock (_dataFileLock)
{
- var encrypted = File.ReadAllText(path, Encoding.UTF8);
+ var encrypted = _fileSystem.ReadAllText(path, Encoding.UTF8);
var json = _encryption.DecryptString(encrypted);
@@ -932,7 +936,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
var length = response.ContentLength;
- if (length != new FileInfo(user.GetImageInfo(ImageType.Primary, 0).Path).Length)
+ if (length != _fileSystem.GetFileInfo(user.GetImageInfo(ImageType.Primary, 0).Path).Length)
{
changed = true;
}
@@ -943,7 +947,7 @@ namespace MediaBrowser.Server.Implementations.Connect
{
await _providerManager.SaveImage(user, imageUrl, _connectImageSemaphore, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
- await user.RefreshMetadata(new MetadataRefreshOptions
+ await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true,
@@ -1076,20 +1080,25 @@ namespace MediaBrowser.Server.Implementations.Connect
var url = GetConnectUrl("keyAssociation");
- url += "?serverId=" + ConnectServerId;
- url += "&supporterKey=" + _securityManager.SupporterKey;
-
var options = new HttpRequestOptions
{
Url = url,
CancellationToken = CancellationToken.None
};
+ var postData = new Dictionary<string, string>
+ {
+ {"serverId", ConnectServerId},
+ {"supporterKey", _securityManager.SupporterKey}
+ };
+
+ options.SetPostData(postData);
+
SetServerAccessToken(options);
SetApplicationHeader(options);
// No need to examine the response
- using (var stream = (await _httpClient.SendAsync(options, "GET").ConfigureAwait(false)).Content)
+ using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content)
{
return _json.DeserializeFromStream<ConnectSupporterSummary>(stream);
}
@@ -1104,16 +1113,21 @@ namespace MediaBrowser.Server.Implementations.Connect
var url = GetConnectUrl("keyAssociation");
- url += "?serverId=" + ConnectServerId;
- url += "&supporterKey=" + _securityManager.SupporterKey;
- url += "&userId=" + id;
-
var options = new HttpRequestOptions
{
Url = url,
CancellationToken = CancellationToken.None
};
+ var postData = new Dictionary<string, string>
+ {
+ {"serverId", ConnectServerId},
+ {"supporterKey", _securityManager.SupporterKey},
+ {"userId", id}
+ };
+
+ options.SetPostData(postData);
+
SetServerAccessToken(options);
SetApplicationHeader(options);
@@ -1132,16 +1146,21 @@ namespace MediaBrowser.Server.Implementations.Connect
var url = GetConnectUrl("keyAssociation");
- url += "?serverId=" + ConnectServerId;
- url += "&supporterKey=" + _securityManager.SupporterKey;
- url += "&userId=" + id;
-
var options = new HttpRequestOptions
{
Url = url,
CancellationToken = CancellationToken.None
};
+ var postData = new Dictionary<string, string>
+ {
+ {"serverId", ConnectServerId},
+ {"supporterKey", _securityManager.SupporterKey},
+ {"userId", id}
+ };
+
+ options.SetPostData(postData);
+
SetServerAccessToken(options);
SetApplicationHeader(options);
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
index 566f4c5f4..6d7265972 100644
--- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -3,6 +3,8 @@ using MediaBrowser.Controller.Entities;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Devices
{
@@ -51,17 +53,19 @@ namespace MediaBrowser.Server.Implementations.Devices
public class CameraUploadsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public CameraUploadsDynamicFolder(IApplicationPaths appPaths)
+ public CameraUploadsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "camerauploads");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new CameraUploadsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
index 0173f2784..0b2c082a8 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -17,6 +17,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Devices
{
@@ -157,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.Devices
_libraryMonitor.ReportFileSystemChangeBeginning(path);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
try
{
@@ -264,6 +265,11 @@ namespace MediaBrowser.Server.Implementations.Devices
return true;
}
+ if (policy.IsAdministrator)
+ {
+ return true;
+ }
+
return ListHelper.ContainsIgnoreCase(policy.EnabledDevices, id);
}
}
@@ -290,4 +296,4 @@ namespace MediaBrowser.Server.Implementations.Devices
return config.GetConfiguration<DevicesOptions>("devices");
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
index 6d324b1ab..43b1e693c 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceRepository.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Devices
{
@@ -47,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Devices
public Task SaveDevice(DeviceInfo device)
{
var path = Path.Combine(GetDevicePath(device.Id), "device.json");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_syncLock)
{
@@ -111,8 +112,8 @@ namespace MediaBrowser.Server.Implementations.Devices
try
{
- return Directory
- .EnumerateFiles(path, "*", SearchOption.AllDirectories)
+ return _fileSystem
+ .GetFilePaths(path, true)
.Where(i => string.Equals(Path.GetFileName(i), "device.json", StringComparison.OrdinalIgnoreCase))
.ToList()
.Select(i =>
@@ -178,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Devices
public void AddCameraUpload(string deviceId, LocalFileInfo file)
{
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_syncLock)
{
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index edfef38fd..20e1eb543 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -26,6 +26,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Dto
{
@@ -397,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.Dto
else if (item is LiveTvProgram)
{
- _livetvManager().AddInfoToProgramDto(item, dto, user);
+ _livetvManager().AddInfoToProgramDto(item, dto, fields.Contains(ItemFields.ChannelInfo), user);
}
return dto;
@@ -908,12 +909,6 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.DisplayMediaType = item.DisplayMediaType;
}
- // Leave null if false
- if (item.IsUnidentified)
- {
- dto.IsUnidentified = item.IsUnidentified;
- }
-
if (fields.Contains(ItemFields.Settings))
{
dto.LockedFields = item.LockedFields;
@@ -1047,14 +1042,10 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.IsFolder = item.IsFolder;
dto.MediaType = item.MediaType;
dto.LocationType = item.LocationType;
+ dto.IsHD = item.IsHD;
- var hasLang = item as IHasPreferredMetadataLanguage;
-
- if (hasLang != null)
- {
- dto.PreferredMetadataCountryCode = hasLang.PreferredMetadataCountryCode;
- dto.PreferredMetadataLanguage = hasLang.PreferredMetadataLanguage;
- }
+ dto.PreferredMetadataCountryCode = item.PreferredMetadataCountryCode;
+ dto.PreferredMetadataLanguage = item.PreferredMetadataLanguage;
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
@@ -1318,7 +1309,11 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.VideoType = video.VideoType;
dto.Video3DFormat = video.Video3DFormat;
dto.IsoType = video.IsoType;
- dto.IsHD = video.IsHD;
+
+ if (video.HasSubtitles)
+ {
+ dto.HasSubtitles = video.HasSubtitles;
+ }
if (video.AdditionalParts.Count != 0)
{
@@ -1433,8 +1428,6 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.AirTime = series.AirTime;
dto.SeriesStatus = series.Status;
- dto.SeasonCount = series.SeasonCount;
-
if (fields.Contains(ItemFields.Settings))
{
dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
@@ -1590,7 +1583,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
foreach (var map in _config.Configuration.PathSubstitutions)
{
- path = _fileSystem.SubstitutePath(path, map.From, map.To);
+ path = _libraryManager.SubstitutePath(path, map.From, map.To);
}
}
@@ -1755,13 +1748,11 @@ namespace MediaBrowser.Server.Implementations.Dto
{
var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
- if (imageInfo == null)
+ if (imageInfo == null || !imageInfo.IsLocalFile)
{
return;
}
- var path = imageInfo.Path;
-
ImageSize size;
try
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index fa5841bb8..a2ffa9aff 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -147,7 +147,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
// It also can fail with others like 727-ExternalPortOnlySupportsWildcard, 728-NoPortMapsAvailable
// and those errors (upnp errors) could be useful for diagnosting.
- _logger.ErrorException("Error creating port forwarding rules", ex);
+ // Commenting out because users are reporting problems out of our control
+ //_logger.ErrorException("Error creating port forwarding rules", ex);
}
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
index d5b7f5b36..9a20505a5 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
@@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
@@ -60,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
var dataPath = Path.Combine(_appPaths.DataPath, "remotenotifications.json");
- var lastRunTime = File.Exists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
+ var lastRunTime = _fileSystem.FileExists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
try
{
@@ -88,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
{
var notifications = _json.DeserializeFromStream<RemoteNotification[]>(stream);
- File.WriteAllText(dataPath, string.Empty);
+ _fileSystem.WriteAllText(dataPath, string.Empty);
await CreateNotifications(notifications, lastRunTime).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 06b72e4ef..e36813d11 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
@@ -182,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath);
result.TargetPath = newPath;
- var fileExists = File.Exists(result.TargetPath);
+ var fileExists = _fileSystem.FileExists(result.TargetPath);
var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
if (!overwriteExisting)
@@ -256,7 +257,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (!string.IsNullOrWhiteSpace(originalFilenameWithoutExtension) && !string.IsNullOrWhiteSpace(directory))
{
// Get all related files, e.g. metadata, images, etc
- var files = Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly)
+ var files = _fileSystem.GetFilePaths(directory)
.Where(i => (Path.GetFileNameWithoutExtension(i) ?? string.Empty).StartsWith(originalFilenameWithoutExtension, StringComparison.OrdinalIgnoreCase))
.ToList();
@@ -272,7 +273,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var destination = Path.Combine(directory, filename);
- File.Move(file, destination);
+ _fileSystem.MoveFile(file, destination);
}
}
}
@@ -313,7 +314,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
try
{
- var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly)
+ var filesOfOtherExtensions = _fileSystem.GetFilePaths(folder)
.Where(i => _libraryManager.IsVideoFile(i) && string.Equals(_fileSystem.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase));
episodePaths.AddRange(filesOfOtherExtensions);
@@ -332,19 +333,19 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
- Directory.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
- var targetAlreadyExists = File.Exists(result.TargetPath);
+ var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath);
try
{
if (targetAlreadyExists || options.CopyOriginalFile)
{
- File.Copy(result.OriginalPath, result.TargetPath, true);
+ _fileSystem.CopyFile(result.OriginalPath, result.TargetPath, true);
}
else
{
- File.Move(result.OriginalPath, result.TargetPath);
+ _fileSystem.MoveFile(result.OriginalPath, result.TargetPath);
}
result.Status = FileSortingStatus.Success;
@@ -435,7 +436,26 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var newPath = GetSeasonFolderPath(series, seasonNumber, options);
- var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options);
+ // MAX_PATH - trailing <NULL> charachter - drive component: 260 - 1 - 3 = 256
+ // Usually newPath would include the drive component, but use 256 to be sure
+ var maxFilenameLength = 256 - newPath.Length;
+
+ if (!newPath.EndsWith(@"\"))
+ {
+ // Remove 1 for missing backslash combining path and filename
+ maxFilenameLength--;
+ }
+
+ // Remove additional 4 chars to prevent PathTooLongException for downloaded subtitles (eg. filename.ext.eng.srt)
+ maxFilenameLength -= 4;
+
+ var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options, maxFilenameLength);
+
+ if (string.IsNullOrEmpty(episodeFileName))
+ {
+ // cause failure
+ return string.Empty;
+ }
newPath = Path.Combine(newPath, episodeFileName);
@@ -481,7 +501,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName));
}
- private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options)
+ private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options, int? maxLength)
{
seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim();
@@ -497,9 +517,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
.Replace("%0s", seasonNumber.ToString("00", _usCulture))
.Replace("%00s", seasonNumber.ToString("000", _usCulture))
.Replace("%ext", sourceExtension)
- .Replace("%en", episodeTitle)
- .Replace("%e.n", episodeTitle.Replace(" ", "."))
- .Replace("%e_n", episodeTitle.Replace(" ", "_"));
+ .Replace("%en", "%#1")
+ .Replace("%e.n", "%#2")
+ .Replace("%e_n", "%#3");
if (endingEpisodeNumber.HasValue)
{
@@ -508,9 +528,37 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
.Replace("%00ed", endingEpisodeNumber.Value.ToString("000", _usCulture));
}
- return result.Replace("%e", episodeNumber.ToString(_usCulture))
+ result = result.Replace("%e", episodeNumber.ToString(_usCulture))
.Replace("%0e", episodeNumber.ToString("00", _usCulture))
.Replace("%00e", episodeNumber.ToString("000", _usCulture));
+
+ if (maxLength.HasValue && result.Contains("%#"))
+ {
+ // Substract 3 for the temp token length (%#1, %#2 or %#3)
+ int maxRemainingTitleLength = maxLength.Value - result.Length + 3;
+ string shortenedEpisodeTitle = string.Empty;
+
+ if (maxRemainingTitleLength > 5)
+ {
+ // A title with fewer than 5 letters wouldn't be of much value
+ shortenedEpisodeTitle = episodeTitle.Substring(0, Math.Min(maxRemainingTitleLength, episodeTitle.Length));
+ }
+
+ result = result.Replace("%#1", shortenedEpisodeTitle)
+ .Replace("%#2", shortenedEpisodeTitle.Replace(" ", "."))
+ .Replace("%#3", shortenedEpisodeTitle.Replace(" ", "_"));
+ }
+
+ if (maxLength.HasValue && result.Length > maxLength.Value)
+ {
+ // There may be cases where reducing the title length may still not be sufficient to
+ // stay below maxLength
+ var msg = string.Format("Unable to generate an episode file name shorter than {0} characters to constrain to the max path limit", maxLength);
+ _logger.Warn(msg);
+ return string.Empty;
+ }
+
+ return result;
}
private bool IsSameEpisode(string sourcePath, string newPath)
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
index a6116ab09..839a85adb 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
@@ -13,6 +13,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
index f993e1fc3..f1fe5539f 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
index 0caa8c26e..3e5296639 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
@@ -11,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
@@ -35,17 +36,33 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_providerManager = providerManager;
}
- public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress)
+ private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options)
{
var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
+ try
+ {
+ return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error organizing file {0}", ex, fileInfo.Name);
+ }
+
+ return false;
+ }
+
+ public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress)
+ {
var watchLocations = options.WatchLocations.ToList();
var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
.OrderBy(_fileSystem.GetCreationTimeUtc)
- .Where(i => _libraryManager.IsVideoFile(i.FullName) && i.Length >= minFileBytes)
+ .Where(i => EnableOrganization(i, options))
.ToList();
+ var processedFolders = new HashSet<string>();
+
progress.Report(10);
if (eligibleFiles.Count > 0)
@@ -59,7 +76,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
try
{
- await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
+ var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
+ if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
+ {
+ processedFolders.Add(file.DirectoryName);
+ }
}
catch (Exception ex)
{
@@ -77,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
cancellationToken.ThrowIfCancellationRequested();
progress.Report(99);
- foreach (var path in watchLocations)
+ foreach (var path in processedFolders)
{
var deleteExtensions = options.LeftOverFileExtensionsToDelete
.Select(i => i.Trim().TrimStart('.'))
@@ -92,9 +113,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
if (options.DeleteEmptyFolders)
{
- foreach (var subfolder in GetDirectories(path).ToList())
+ if (!IsWatchFolder(path, watchLocations))
{
- DeleteEmptyFolders(subfolder);
+ DeleteEmptyFolders(path);
}
}
}
@@ -103,44 +124,22 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
/// <summary>
- /// Gets the directories.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- private IEnumerable<string> GetDirectories(string path)
- {
- try
- {
- return Directory
- .EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly)
- .ToList();
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error getting files from {0}", ex, path);
-
- return new List<string>();
- }
- }
-
- /// <summary>
/// Gets the files to organize.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>IEnumerable{FileInfo}.</returns>
- private IEnumerable<FileInfo> GetFilesToOrganize(string path)
+ private List<FileSystemMetadata> GetFilesToOrganize(string path)
{
try
{
- return new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ return _fileSystem.GetFiles(path, true)
.ToList();
}
catch (IOException ex)
{
_logger.ErrorException("Error getting files from {0}", ex, path);
- return new List<FileInfo>();
+ return new List<FileSystemMetadata>();
}
}
@@ -151,8 +150,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="extensions">The extensions.</param>
private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions)
{
- var eligibleFiles = new DirectoryInfo(path)
- .EnumerateFiles("*", SearchOption.AllDirectories)
+ var eligibleFiles = _fileSystem.GetFiles(path, true)
.Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
.ToList();
@@ -177,19 +175,19 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
try
{
- foreach (var d in Directory.EnumerateDirectories(path))
+ foreach (var d in _fileSystem.GetDirectoryPaths(path))
{
DeleteEmptyFolders(d);
}
- var entries = Directory.EnumerateFileSystemEntries(path);
+ var entries = _fileSystem.GetFileSystemEntryPaths(path);
if (!entries.Any())
{
try
{
_logger.Debug("Deleting empty directory {0}", path);
- Directory.Delete(path);
+ _fileSystem.DeleteDirectory(path, false);
}
catch (UnauthorizedAccessException) { }
catch (DirectoryNotFoundException) { }
@@ -197,5 +195,15 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
catch (UnauthorizedAccessException) { }
}
+
+ /// <summary>
+ /// Determines if a given folder path is contained in a folder list
+ /// </summary>
+ /// <param name="path">The folder path to check.</param>
+ /// <param name="watchLocations">A list of folders.</param>
+ private bool IsWatchFolder(string path, IEnumerable<string> watchLocations)
+ {
+ return watchLocations.Contains(path, StringComparer.OrdinalIgnoreCase);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 3795f4b15..e8bb40ba1 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -79,6 +79,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
_containerAdapter = new ContainerAdapter(applicationHost);
}
+ public string GlobalResponse { get; set; }
+
public override void Configure(Container container)
{
HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath;
@@ -90,7 +92,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{typeof (FileNotFoundException), 404},
{typeof (DirectoryNotFoundException), 404},
{typeof (SecurityException), 401},
- {typeof (UnauthorizedAccessException), 401}
+ {typeof (UnauthorizedAccessException), 500}
};
HostConfig.Instance.DebugMode = true;
@@ -336,6 +338,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return Task.FromResult(true);
}
+ if (!string.IsNullOrWhiteSpace(GlobalResponse))
+ {
+ httpRes.Write(GlobalResponse);
+ httpRes.ContentType = "text/plain";
+ return Task.FromResult(true);
+ }
+
var handler = HttpHandlerFactory.GetHandler(httpReq);
var remoteIp = httpReq.RemoteIp;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index 961d58eb6..080441dda 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
+using CommonIO;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace MediaBrowser.Server.Implementations.HttpServer
@@ -476,7 +477,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return new StreamWriter(stream, contentType, _logger)
{
- OnComplete = options.OnComplete
+ OnComplete = options.OnComplete,
+ OnError = options.OnError
};
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
index 5558c24d7..f038591aa 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var msg = "HTTP Response " + statusCode + " to " + endPoint + responseTime;
- logger.LogMultiline(msg, LogSeverity.Debug, log);
+ logger.LogMultiline(msg, LogSeverity.Info, log);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
index b4da40702..f6b14fcab 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -220,7 +220,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
{
if (string.IsNullOrWhiteSpace(token))
{
- throw new SecurityException("Access token is invalid or expired.");
+ throw new SecurityException("Access token is required.");
}
var info = GetTokenInfo(request);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 80892b96c..509a00ff9 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -62,52 +62,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
auth.TryGetValue("Version", out version);
}
- var token = httpReq.Headers["X-MediaBrowser-Token"];
+ var token = httpReq.Headers["X-Emby-Token"];
if (string.IsNullOrWhiteSpace(token))
{
- token = httpReq.QueryString["api_key"];
+ token = httpReq.Headers["X-MediaBrowser-Token"];
}
-
- // Hack until iOS is updated
- // TODO: Remove
- if (string.IsNullOrWhiteSpace(client))
- {
- var userAgent = httpReq.Headers["User-Agent"] ?? string.Empty;
-
- if (userAgent.IndexOf("mediabrowserios", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1)
- {
- client = "iOS";
- }
-
- else if (userAgent.IndexOf("crKey", StringComparison.OrdinalIgnoreCase) != -1)
- {
- client = "Chromecast";
- }
- }
-
- // Hack until iOS is updated
- // TODO: Remove
- if (string.IsNullOrWhiteSpace(device))
+ if (string.IsNullOrWhiteSpace(token))
{
- var userAgent = httpReq.Headers["User-Agent"] ?? string.Empty;
-
- if (userAgent.IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "iPhone";
- }
-
- else if (userAgent.IndexOf("iPad", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "iPad";
- }
-
- else if (userAgent.IndexOf("crKey", StringComparison.OrdinalIgnoreCase) != -1)
- {
- device = "Chromecast";
- }
+ token = httpReq.QueryString["api_key"];
}
var info = new AuthorizationInfo
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index fdb27d40d..f8178c115 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -191,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
var type = request.IsWebSocketRequest ? "Web Socket" : "HTTP " + request.HttpMethod;
- logger.LogMultiline(type + " " + request.Url, LogSeverity.Debug, log);
+ logger.LogMultiline(type + " " + request.Url, LogSeverity.Info, log);
}
private void HandleError(Exception ex, HttpListenerContext context)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
index daa5b86d9..a756f4aa8 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
@@ -36,6 +36,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
public Action OnComplete { get; set; }
+ public Action OnError { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
@@ -102,6 +103,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
Logger.ErrorException("Error streaming data", ex);
+ if (OnError != null)
+ {
+ OnError();
+ }
+
throw;
}
finally
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 5bd26ce18..e107ea9f1 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -15,6 +15,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Controller;
namespace MediaBrowser.Server.Implementations.IO
{
@@ -86,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.IO
// This is an arbitraty amount of time, but delay it because file system writes often trigger events long after the file was actually written to.
// Seeing long delays in some situations, especially over the network, sometimes up to 45 seconds
// But if we make this delay too high, we risk missing legitimate changes, such as user adding a new file, or hand-editing metadata
- await Task.Delay(20000).ConfigureAwait(false);
+ await Task.Delay(25000).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
@@ -113,11 +115,12 @@ namespace MediaBrowser.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
+ private readonly IServerApplicationHost _appHost;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
/// </summary>
- public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
+ public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IServerApplicationHost appHost)
{
if (taskManager == null)
{
@@ -129,6 +132,7 @@ namespace MediaBrowser.Server.Implementations.IO
Logger = logManager.GetLogger(GetType().Name);
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
+ _appHost = appHost;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
@@ -156,7 +160,7 @@ namespace MediaBrowser.Server.Implementations.IO
switch (ConfigurationManager.Configuration.EnableLibraryMonitor)
{
case AutoOnOff.Auto:
- return Environment.OSVersion.Platform == PlatformID.Win32NT;
+ return _appHost.SupportsLibraryMonitor;
case AutoOnOff.Enabled:
return true;
default:
@@ -645,7 +649,7 @@ namespace MediaBrowser.Server.Implementations.IO
if (item != null)
{
// If the item has been deleted find the first valid parent that still exists
- while (!Directory.Exists(item.Path) && !File.Exists(item.Path))
+ while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
{
item = item.Parent;
diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
index db9841f9d..ec94e16db 100644
--- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
+++ b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
@@ -15,6 +15,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Intros
{
@@ -25,14 +27,16 @@ namespace MediaBrowser.Server.Implementations.Intros
private readonly ILocalizationManager _localization;
private readonly IConfigurationManager _serverConfig;
private readonly ILibraryManager _libraryManager;
+ private readonly IFileSystem _fileSystem;
- public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager)
+ public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem)
{
_security = security;
_channelManager = channelManager;
_localization = localization;
_serverConfig = serverConfig;
_libraryManager = libraryManager;
+ _fileSystem = fileSystem;
}
public async Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, User user)
@@ -79,8 +83,16 @@ namespace MediaBrowser.Server.Implementations.Intros
if (config.EnableIntrosFromMoviesInLibrary)
{
- var itemsWithTrailers = user.RootFolder
- .GetRecursiveChildren(user, i =>
+ var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Movie).Name },
+
+ User = user
+
+ }).Items;
+
+ var itemsWithTrailers = inputItems
+ .Where(i =>
{
var hasTrailers = i as IHasTrailers;
@@ -232,7 +244,7 @@ namespace MediaBrowser.Server.Implementations.Intros
return new List<string>();
}
- return Directory.EnumerateFiles(options.CustomIntroPath, "*", SearchOption.AllDirectories)
+ return _fileSystem.GetFilePaths(options.CustomIntroPath, true)
.Where(_libraryManager.IsVideoFile);
}
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
index be8c1cfbd..9035d6479 100644
--- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library
{
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index cc9d9551c..92acd08d1 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -34,6 +34,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Model.Extensions;
using MoreLinq;
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
@@ -354,6 +356,10 @@ namespace MediaBrowser.Server.Implementations.Library
return;
}
}
+ //if (!(item is Folder))
+ //{
+ // return;
+ //}
LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; });
}
@@ -395,12 +401,12 @@ namespace MediaBrowser.Server.Implementations.Library
{
foreach (var path in item.GetDeletePaths().ToList())
{
- if (Directory.Exists(path))
+ if (_fileSystem.DirectoryExists(path))
{
_logger.Debug("Deleting path {0}", path);
_fileSystem.DeleteDirectory(path, true);
}
- else if (File.Exists(path))
+ else if (_fileSystem.FileExists(path))
{
_logger.Debug("Deleting path {0}", path);
_fileSystem.DeleteFile(path);
@@ -545,13 +551,13 @@ namespace MediaBrowser.Server.Implementations.Library
return item;
}
- public BaseItem ResolvePath(FileSystemInfo fileInfo,
+ public BaseItem ResolvePath(FileSystemMetadata fileInfo,
Folder parent = null)
{
- return ResolvePath(fileInfo, new DirectoryService(_logger), parent);
+ return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), parent);
}
- private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
+ private BaseItem ResolvePath(FileSystemMetadata fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
{
if (fileInfo == null)
{
@@ -595,7 +601,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var paths = NormalizeRootPathList(fileSystemDictionary.Keys);
- fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+ fileSystemDictionary = paths.Select(_fileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
}
args.FileSystemDictionary = fileSystemDictionary;
@@ -638,7 +644,7 @@ namespace MediaBrowser.Server.Implementations.Library
return !args.ContainsFileSystemEntryByName(".ignore");
}
- public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType)
+ public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, string collectionType)
{
var fileList = files.ToList();
@@ -666,7 +672,7 @@ namespace MediaBrowser.Server.Implementations.Library
return ResolveFileList(fileList, directoryService, parent, collectionType);
}
- private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemInfo> fileList, IDirectoryService directoryService, Folder parent, string collectionType)
+ private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> fileList, IDirectoryService directoryService, Folder parent, string collectionType)
{
return fileList.Select(f =>
{
@@ -691,9 +697,9 @@ namespace MediaBrowser.Server.Implementations.Library
{
var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
- Directory.CreateDirectory(rootFolderPath);
+ _fileSystem.CreateDirectory(rootFolderPath);
- var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath));
+ var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
// Add in the plug-in folders
foreach (var child in PluginFolderCreators)
@@ -742,13 +748,13 @@ namespace MediaBrowser.Server.Implementations.Library
{
var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- Directory.CreateDirectory(userRootPath);
+ _fileSystem.CreateDirectory(userRootPath);
var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder;
if (tmpItem == null)
{
- tmpItem = (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath));
+ tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
}
_userRootFolder = tmpItem;
@@ -1007,9 +1013,9 @@ namespace MediaBrowser.Server.Implementations.Library
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
// Ensure the location is available.
- Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
+ _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
- return new PeopleValidator(this, _logger, ConfigurationManager).ValidatePeople(cancellationToken, progress);
+ return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress);
}
/// <summary>
@@ -1064,7 +1070,7 @@ namespace MediaBrowser.Server.Implementations.Library
progress.Report(.5);
// Start by just validating the children of the root, but go no further
- await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(), recursive: false);
+ await RootFolder.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false);
progress.Report(1);
@@ -1072,7 +1078,7 @@ namespace MediaBrowser.Server.Implementations.Library
await userRoot.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(), recursive: false).ConfigureAwait(false);
+ await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false);
progress.Report(2);
var innerProgress = new ActionableProgress<double>();
@@ -1080,7 +1086,7 @@ namespace MediaBrowser.Server.Implementations.Library
innerProgress.RegisterAction(pct => progress.Report(2 + pct * .73));
// Now validate the entire media library
- await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(), recursive: true).ConfigureAwait(false);
+ await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: true).ConfigureAwait(false);
progress.Report(75);
@@ -1165,23 +1171,45 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>IEnumerable{VirtualFolderInfo}.</returns>
private IEnumerable<VirtualFolderInfo> GetView(string path)
{
- return Directory.EnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly)
- .Select(dir => new VirtualFolderInfo
- {
- Name = Path.GetFileName(dir),
+ var topLibraryFolders = GetUserRootFolder().Children.ToList();
- Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
- .Select(_fileSystem.ResolveShortcut)
- .OrderBy(i => i)
- .ToList(),
+ return _fileSystem.GetDirectoryPaths(path)
+ .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders));
+ }
- CollectionType = GetCollectionType(dir)
- });
+ private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> collectionFolders)
+ {
+ var info = new VirtualFolderInfo
+ {
+ Name = Path.GetFileName(dir),
+
+ Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
+ .Select(_fileSystem.ResolveShortcut)
+ .OrderBy(i => i)
+ .ToList(),
+
+ CollectionType = GetCollectionType(dir)
+ };
+
+ var libraryFolder = collectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase));
+
+ if (libraryFolder != null && libraryFolder.HasImage(ImageType.Primary))
+ {
+ info.PrimaryImageItemId = libraryFolder.Id.ToString("N");
+ }
+
+ if (libraryFolder != null)
+ {
+ info.ItemId = libraryFolder.Id.ToString("N");
+ }
+
+ return info;
}
private string GetCollectionType(string path)
{
- return new DirectoryInfo(path).EnumerateFiles("*.collection", SearchOption.TopDirectoryOnly)
+ return _fileSystem.GetFiles(path, false)
+ .Where(i => string.Equals(i.Extension, ".collection", StringComparison.OrdinalIgnoreCase))
.Select(i => _fileSystem.GetFileNameWithoutExtension(i))
.FirstOrDefault();
}
@@ -1638,6 +1666,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
+ //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
public Task<UserView> GetNamedView(User user,
string name,
@@ -1645,12 +1674,7 @@ namespace MediaBrowser.Server.Implementations.Library
string sortName,
CancellationToken cancellationToken)
{
- if (ConfigurationManager.Configuration.EnableUserSpecificUserViews)
- {
- return GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken);
- }
-
- return GetNamedView(name, viewType, sortName, cancellationToken);
+ return GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken);
}
public async Task<UserView> GetNamedView(string name,
@@ -1671,7 +1695,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null ||
!string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1696,13 +1720,19 @@ namespace MediaBrowser.Server.Implementations.Library
if (!refresh)
{
- refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
+ refresh = (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
+ }
+
+ if (!refresh && item.DisplayParentId != Guid.Empty)
+ {
+ var displayParent = GetItemById(item.DisplayParentId);
+ refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
}
if (refresh)
{
await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Not sure why this is necessary but need to figure it out
// View images are not getting utilized without this
@@ -1758,7 +1788,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null)
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1767,12 +1797,13 @@ namespace MediaBrowser.Server.Implementations.Library
DateCreated = DateTime.UtcNow,
Name = name,
ViewType = viewType,
- ForcedSortName = sortName
+ ForcedSortName = sortName,
+ UserId = user.Id
};
if (!string.IsNullOrWhiteSpace(parentId))
{
- item.ParentId = new Guid(parentId);
+ item.DisplayParentId = new Guid(parentId);
}
await CreateItem(item, cancellationToken).ConfigureAwait(false);
@@ -1780,17 +1811,29 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true;
}
+ if (!item.UserId.HasValue)
+ {
+ item.UserId = user.Id;
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
{
item.ViewType = viewType;
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
}
- var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
+ var refresh = isNew || (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
+
+ if (!refresh && item.DisplayParentId != Guid.Empty)
+ {
+ var displayParent = GetItemById(item.DisplayParentId);
+ refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
+ }
if (refresh)
{
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Need to force save to increment DateLastSaved
ForceSave = true
@@ -1800,6 +1843,81 @@ namespace MediaBrowser.Server.Implementations.Library
return item;
}
+ public async Task<UserView> GetShadowView(BaseItem parent,
+ string viewType,
+ string sortName,
+ string uniqueId,
+ CancellationToken cancellationToken)
+ {
+ if (parent == null)
+ {
+ throw new ArgumentNullException("parent");
+ }
+
+ var name = parent.Name;
+ var parentId = parent.Id;
+
+ var idValues = "37_namedview_" + name + parentId + (viewType ?? string.Empty);
+ if (!string.IsNullOrWhiteSpace(uniqueId))
+ {
+ idValues += uniqueId;
+ }
+
+ var id = GetNewItemId(idValues, typeof(UserView));
+
+ var path = parent.Path;
+
+ var item = GetItemById(id) as UserView;
+
+ var isNew = false;
+
+ if (item == null)
+ {
+ _fileSystem.CreateDirectory(path);
+
+ item = new UserView
+ {
+ Path = path,
+ Id = id,
+ DateCreated = DateTime.UtcNow,
+ Name = name,
+ ViewType = viewType,
+ ForcedSortName = sortName
+ };
+
+ item.DisplayParentId = parentId;
+
+ await CreateItem(item, cancellationToken).ConfigureAwait(false);
+
+ isNew = true;
+ }
+
+ if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
+ {
+ item.ViewType = viewType;
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+ }
+
+ var refresh = isNew || (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
+
+ if (!refresh && item.DisplayParentId != Guid.Empty)
+ {
+ var displayParent = GetItemById(item.DisplayParentId);
+ refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
+ }
+
+ if (refresh)
+ {
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
+ {
+ // Need to force save to increment DateLastSaved
+ ForceSave = true
+ });
+ }
+
+ return item;
+ }
+
public async Task<UserView> GetNamedView(string name,
string parentId,
string viewType,
@@ -1828,7 +1946,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (item == null)
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
item = new UserView
{
@@ -1842,7 +1960,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (!string.IsNullOrWhiteSpace(parentId))
{
- item.ParentId = new Guid(parentId);
+ item.DisplayParentId = new Guid(parentId);
}
await CreateItem(item, cancellationToken).ConfigureAwait(false);
@@ -1856,11 +1974,17 @@ namespace MediaBrowser.Server.Implementations.Library
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
}
- var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
+ var refresh = isNew || (DateTime.UtcNow - item.DateLastRefreshed) >= _viewRefreshInterval;
+
+ if (!refresh && item.DisplayParentId != Guid.Empty)
+ {
+ var displayParent = GetItemById(item.DisplayParentId);
+ refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
+ }
if (refresh)
{
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
{
// Need to force save to increment DateLastSaved
ForceSave = true
@@ -2043,11 +2167,11 @@ namespace MediaBrowser.Server.Implementations.Library
};
}
- public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+ public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = fileSystemChildren.OfType<DirectoryInfo>()
+ var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
+ .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
.ToList();
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
@@ -2063,7 +2187,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (currentVideo != null)
{
- files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => new FileInfo(i.Path)));
+ files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
}
return ResolvePaths(files, directoryService, null, null)
@@ -2086,11 +2210,11 @@ namespace MediaBrowser.Server.Implementations.Library
}).OrderBy(i => i.Path).ToList();
}
- public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+ public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
- var files = fileSystemChildren.OfType<DirectoryInfo>()
+ var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
+ .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
.ToList();
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
@@ -2106,7 +2230,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (currentVideo != null)
{
- files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => new FileInfo(i.Path)));
+ files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
}
return ResolvePaths(files, directoryService, null, null)
@@ -2129,6 +2253,38 @@ namespace MediaBrowser.Server.Implementations.Library
}).OrderBy(i => i.Path).ToList();
}
+ public string SubstitutePath(string path, string from, string to)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+ if (string.IsNullOrWhiteSpace(from))
+ {
+ throw new ArgumentNullException("from");
+ }
+ if (string.IsNullOrWhiteSpace(to))
+ {
+ throw new ArgumentNullException("to");
+ }
+
+ var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
+
+ if (!string.Equals(newPath, path))
+ {
+ if (to.IndexOf('/') != -1)
+ {
+ newPath = newPath.Replace('\\', '/');
+ }
+ else
+ {
+ newPath = newPath.Replace('/', '\\');
+ }
+ }
+
+ return newPath;
+ }
+
private void SetExtraTypeFromFilename(Video item)
{
var resolver = new ExtraResolver(GetNamingOptions(), new PatternsLogger(), new RegexProvider());
@@ -2181,7 +2337,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- return item.People ?? new List<PersonInfo>();
+ return new List<PersonInfo>();
}
public List<Person> GetPeopleItems(InternalPeopleQuery query)
@@ -2222,5 +2378,17 @@ namespace MediaBrowser.Server.Implementations.Library
return ItemRepository.UpdatePeople(item.Id, people);
}
+
+ private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1,1);
+ public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
+ {
+ _logger.Debug("ConvertImageToLocal item {0}", item.Id);
+
+ await _providerManagerFactory().SaveImage(item, image.Path, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
+
+ await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
+
+ return item.GetImageInfo(image.Type, imageIndex);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 63067bf5a..9694965c7 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -15,6 +15,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -24,17 +26,19 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
private readonly IJsonSerializer _jsonSerializer;
+ private readonly IFileSystem _fileSystem;
private IMediaSourceProvider[] _providers;
private readonly ILogger _logger;
- public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer)
+ public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
{
_itemRepo = itemRepo;
_userManager = userManager;
_libraryManager = libraryManager;
_logger = logger;
_jsonSerializer = jsonSerializer;
+ _fileSystem = fileSystem;
}
public void AddParts(IEnumerable<IMediaSourceProvider> providers)
@@ -77,10 +81,6 @@ namespace MediaBrowser.Server.Implementations.Library
{
return false;
}
- if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
return true;
}
@@ -105,6 +105,18 @@ namespace MediaBrowser.Server.Implementations.Library
return GetMediaStreamsForItem(list);
}
+ private int GetMaxAllowedBitrateForExternalSubtitleStream()
+ {
+ // This is abitrary but at some point it becomes too slow to extract subtitles on the fly
+ // We need to learn more about when this is the case vs. when it isn't
+ if (Environment.ProcessorCount >= 8)
+ {
+ return 10000000;
+ }
+
+ return 2000000;
+ }
+
private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
{
var list = streams.ToList();
@@ -117,9 +129,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
var videoStream = list.FirstOrDefault(i => i.Type == MediaStreamType.Video);
- // This is abitrary but at some point it becomes too slow to extract subtitles on the fly
- // We need to learn more about when this is the case vs. when it isn't
- const int maxAllowedBitrateForExternalSubtitleStream = 10000000;
+ int maxAllowedBitrateForExternalSubtitleStream = GetMaxAllowedBitrateForExternalSubtitleStream();
var videoBitrate = videoStream == null ? maxAllowedBitrateForExternalSubtitleStream : videoStream.BitRate ?? maxAllowedBitrateForExternalSubtitleStream;
@@ -170,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (source.Protocol == MediaProtocol.File)
{
// TODO: Path substitution
- if (!File.Exists(source.Path))
+ if (!_fileSystem.FileExists(source.Path))
{
source.SupportsDirectStream = false;
}
@@ -582,4 +592,4 @@ namespace MediaBrowser.Server.Implementations.Library
public MediaSourceInfo MediaSource;
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
index 683e6c5cc..aee101ef4 100644
--- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
@@ -78,10 +78,19 @@ namespace MediaBrowser.Server.Implementations.Library
public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user)
{
- var inputItems = user.RootFolder
- .GetRecursiveChildren(user, i => i is Audio);
+ var genreList = genres.ToList();
- var genresDictionary = genres.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+ var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+ {
+ IncludeItemTypes = new[] { typeof(Audio).Name },
+
+ Genres = genreList.ToArray(),
+
+ User = user
+
+ }).Items;
+
+ var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
return inputItems
.Cast<Audio>()
@@ -131,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
return GetInstantMixFromFolder(folder, user);
}
-
+
return new Audio[] { };
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
index dac658095..100241d90 100644
--- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
+++ b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
@@ -6,6 +6,7 @@ using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -88,7 +89,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
/// <param name="item">The item.</param>
/// <param name="fileInfo">The file information.</param>
- private static void EnsureName(BaseItem item, FileSystemInfo fileInfo)
+ private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
{
// If the subclass didn't supply a name, add it here
if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
@@ -179,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemInfo info)
+ private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemMetadata info)
{
var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index 0abdc4296..26e767c20 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Server.Implementations.Logging;
using System;
using System.Collections.Generic;
using System.IO;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
@@ -107,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
/// <param name="fileSystem">The file system.</param>
/// <param name="libraryManager">The library manager.</param>
/// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
- private bool ContainsMusic(IEnumerable<FileSystemInfo> list,
+ private bool ContainsMusic(IEnumerable<FileSystemMetadata> list,
bool allowSubfolders,
IDirectoryService directoryService,
ILogger logger,
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 9f3f24865..97a31990e 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 343b6d3a4..fd74b68b8 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -179,10 +179,16 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
{
video.VideoType = VideoType.HdDvd;
+ video.IsHD = true;
}
else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
{
video.VideoType = VideoType.BluRay;
+ video.IsHD = true;
+ }
+ else if (string.Equals(videoInfo.StubType, "hdtv", StringComparison.OrdinalIgnoreCase))
+ {
+ video.IsHD = true;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index ff38e057b..3252db505 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -13,6 +13,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
{
@@ -43,7 +45,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
public MultiItemResolverResult ResolveMultiple(Folder parent,
- List<FileSystemInfo> files,
+ List<FileSystemMetadata> files,
string collectionType,
IDirectoryService directoryService)
{
@@ -61,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
- List<FileSystemInfo> files,
+ List<FileSystemMetadata> files,
string collectionType,
IDirectoryService directoryService)
{
@@ -72,12 +74,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<MusicVideo>(parent, files, directoryService, collectionType, false);
+ return ResolveVideos<MusicVideo>(parent, files, directoryService, false);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
+ return ResolveVideos<Video>(parent, files, directoryService, false);
}
if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
@@ -90,7 +92,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Owned items should just use the plain video type
if (parent == null)
{
- return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
+ return ResolveVideos<Video>(parent, files, directoryService, false);
}
if (parent is Series || parent.Parents.OfType<Series>().Any())
@@ -98,23 +100,23 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
return null;
}
- return ResolveVideos<Movie>(parent, files, directoryService, collectionType, false);
+ return ResolveVideos<Movie>(parent, files, directoryService, false);
}
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<Movie>(parent, files, directoryService, collectionType, true);
+ return ResolveVideos<Movie>(parent, files, directoryService, true);
}
return null;
}
- private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool suppportMultiEditions)
+ private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions)
where T : Video, new()
{
- var files = new List<FileSystemInfo>();
+ var files = new List<FileSystemMetadata>();
var videos = new List<BaseItem>();
- var leftOver = new List<FileSystemInfo>();
+ var leftOver = new List<FileSystemMetadata>();
// Loop through each child file/folder and see if we find a video
foreach (var child in fileSystemEntries)
@@ -343,10 +345,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// <param name="directoryService">The directory service.</param>
/// <param name="collectionType">Type of the collection.</param>
/// <returns>Movie.</returns>
- private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType)
+ private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType)
where T : Video, new()
{
- var multiDiscFolders = new List<FileSystemInfo>();
+ var multiDiscFolders = new List<FileSystemMetadata>();
// Search for a folder rip
foreach (var child in fileSystemEntries)
@@ -394,7 +396,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
!string.Equals(collectionType, CollectionType.Photos) &&
!string.Equals(collectionType, CollectionType.MusicVideos);
- var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType, supportsMultiVersion);
+ var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
if (result.Items.Count == 1)
{
@@ -419,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// <param name="multiDiscFolders">The folders.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>``0.</returns>
- private T GetMultiDiscMovie<T>(List<FileSystemInfo> multiDiscFolders, IDirectoryService directoryService)
+ private T GetMultiDiscMovie<T>(List<FileSystemMetadata> multiDiscFolders, IDirectoryService directoryService)
where T : Video, new()
{
var videoTypes = new List<VideoType>();
@@ -492,7 +494,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
};
}
- private bool IsInvalid(Folder parent, string collectionType, IEnumerable<FileSystemInfo> files)
+ private bool IsInvalid(Folder parent, string collectionType, IEnumerable<FileSystemMetadata> files)
{
if (parent != null)
{
@@ -504,7 +506,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
var validCollectionTypes = new[]
{
- string.Empty,
CollectionType.Movies,
CollectionType.HomeVideos,
CollectionType.MusicVideos,
@@ -512,7 +513,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
CollectionType.Photos
};
- return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ if (string.IsNullOrWhiteSpace(collectionType))
+ {
+ return false;
+ }
+
+ return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
index 31b2d8b0f..cde44122e 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Resolvers;
using System;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers
{
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index c5565eb53..19bd4a1a3 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
{
@@ -99,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
}
public static bool IsSeriesFolder(string path,
- IEnumerable<FileSystemInfo> fileSystemChildren,
+ IEnumerable<FileSystemMetadata> fileSystemChildren,
IDirectoryService directoryService,
IFileSystem fileSystem,
ILogger logger,
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
index d4ff89b4f..d6aff1192 100644
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
@@ -155,18 +155,20 @@ namespace MediaBrowser.Server.Implementations.Library
AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name);
}
+ AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
+
var mediaItems = _libraryManager.GetItems(new InternalItemsQuery
{
NameContains = searchTerm,
ExcludeItemTypes = excludeItemTypes.ToArray(),
IncludeItemTypes = includeItemTypes.ToArray(),
MaxParentalRating = user == null ? null : user.Policy.MaxParentalRating,
- Limit = query.Limit.HasValue ? query.Limit * 3 : null
+ Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 3) : null),
}).Items;
// Add search hints based on item name
- hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user) && !(i is CollectionFolder)).Select(item =>
+ hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user)).Select(item =>
{
var index = GetIndex(item.Name, searchTerm, terms);
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 5012f2479..3c29cf15d 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -30,6 +30,7 @@ using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Library
{
@@ -454,7 +455,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
public Task RefreshUsersMetadata(CancellationToken cancellationToken)
{
- var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken)).ToList();
+ var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken)).ToList();
return Task.WhenAll(tasks);
}
@@ -706,7 +707,8 @@ namespace MediaBrowser.Server.Implementations.Library
Id = Guid.NewGuid(),
DateCreated = DateTime.UtcNow,
DateModified = DateTime.UtcNow,
- UsesIdForConfigurationPath = true
+ UsesIdForConfigurationPath = true,
+ EnableUserViews = true
};
}
@@ -745,7 +747,7 @@ namespace MediaBrowser.Server.Implementations.Library
text.AppendLine(string.Empty);
text.AppendLine("The pin code will expire at " + expiration.ToLocalTime().ToShortDateString() + " " + expiration.ToLocalTime().ToShortTimeString());
- File.WriteAllText(path, text.ToString(), Encoding.UTF8);
+ _fileSystem.WriteAllText(path, text.ToString(), Encoding.UTF8);
var result = new PasswordPinCreationResult
{
@@ -919,7 +921,7 @@ namespace MediaBrowser.Server.Implementations.Library
var path = GetPolifyFilePath(user);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_policySyncLock)
{
@@ -1006,7 +1008,7 @@ namespace MediaBrowser.Server.Implementations.Library
config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
}
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_configSyncLock)
{
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index 43f77ec49..c2938475c 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -27,19 +27,15 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IChannelManager _channelManager;
private readonly ILiveTvManager _liveTvManager;
- private readonly IPlaylistManager _playlists;
- private readonly ICollectionManager _collectionManager;
private readonly IServerConfigurationManager _config;
- public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IPlaylistManager playlists, ICollectionManager collectionManager, IServerConfigurationManager config)
+ public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerConfigurationManager config)
{
_libraryManager = libraryManager;
_localizationManager = localizationManager;
_userManager = userManager;
_channelManager = channelManager;
_liveTvManager = liveTvManager;
- _playlists = playlists;
- _collectionManager = collectionManager;
_config = config;
}
@@ -65,20 +61,26 @@ namespace MediaBrowser.Server.Implementations.Library
var list = new List<Folder>();
- if (_config.Configuration.EnableUserSpecificUserViews)
+ var enableUserViews = _config.Configuration.EnableUserViews || user.EnableUserViews;
+
+ if (enableUserViews)
{
foreach (var folder in standaloneFolders)
{
var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
- if (plainFolderIds.Contains(folder.Id))
+ if (UserView.IsUserSpecific(folder))
{
- list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (plainFolderIds.Contains(folder.Id))
+ {
+ list.Add(await GetUserView(folder, folderViewType, false, string.Empty, cancellationToken).ConfigureAwait(false));
}
else if (!string.IsNullOrWhiteSpace(folderViewType))
{
- list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(folder, folderViewType, true, string.Empty, cancellationToken).ConfigureAwait(false));
}
else
{
@@ -88,7 +90,29 @@ namespace MediaBrowser.Server.Implementations.Library
}
else
{
- list.AddRange(standaloneFolders);
+ // TODO: Deprecate this whole block
+ foreach (var folder in standaloneFolders)
+ {
+ var collectionFolder = folder as ICollectionFolder;
+ var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
+
+ if (UserView.IsUserSpecific(folder))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (plainFolderIds.Contains(folder.Id))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else if (!string.IsNullOrWhiteSpace(folderViewType))
+ {
+ list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ }
+ else
+ {
+ list.Add(folder);
+ }
+ }
}
var parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
@@ -96,7 +120,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (parents.Count > 0)
{
- list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
}
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
@@ -104,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (parents.Count > 0)
{
- list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
}
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.GetViewType(user)))
@@ -112,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (parents.Count > 0)
{
- list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
}
parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Games, StringComparison.OrdinalIgnoreCase))
@@ -120,23 +144,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (parents.Count > 0)
{
- list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
- }
-
- parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, list, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
- }
-
- parents = foldersWithViewTypes.Where(i => string.Equals(i.GetViewType(user), CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, list, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
+ list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, enableUserViews, cancellationToken).ConfigureAwait(false));
}
if (user.Configuration.DisplayFoldersView)
@@ -201,40 +209,18 @@ namespace MediaBrowser.Server.Implementations.Library
return GetUserSubView(name, parentId, type, sortName, cancellationToken);
}
- public async Task<UserView> GetUserView(List<ICollectionFolder> parents, List<Folder> currentViews, string viewType, string sortName, User user, CancellationToken cancellationToken)
+ private async Task<UserView> GetUserView(List<ICollectionFolder> parents, List<Folder> currentViews, string viewType, string sortName, User user, bool enableUserViews, CancellationToken cancellationToken)
{
- var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
- var enableUserSpecificViews = _config.Configuration.EnableUserSpecificUserViews;
-
- if (parents.Count == 1 && parents.All(i => string.Equals((enableUserSpecificViews ? i.CollectionType : i.GetViewType(user)), viewType, StringComparison.OrdinalIgnoreCase)))
+ if (parents.Count == 1 && parents.All(i => string.Equals((enableUserViews ? i.GetViewType(user) : i.CollectionType), viewType, StringComparison.OrdinalIgnoreCase)))
{
- if (!string.IsNullOrWhiteSpace(parents[0].Name))
- {
- name = parents[0].Name;
- }
-
var parentId = parents[0].Id;
var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
- if (!enableRichView || currentViews.OfType<UserView>().Any(i => string.Equals(i.ViewType, viewType, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)))
- {
- return await GetUserView(parentId, name, viewType, enableRichView, sortName, user, cancellationToken).ConfigureAwait(false);
- }
-
- if (enableUserSpecificViews)
- {
- var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
-
- if (view.ParentId != parentId)
- {
- view.ParentId = parentId;
- await view.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
- }
- return view;
- }
+ return await GetUserView((Folder)parents[0], viewType, enableRichView, string.Empty, cancellationToken).ConfigureAwait(false);
}
+ var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
}
@@ -244,6 +230,13 @@ namespace MediaBrowser.Server.Implementations.Library
return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, null, cancellationToken);
}
+ public Task<UserView> GetUserView(Folder parent, string viewType, bool enableRichView, string sortName, CancellationToken cancellationToken)
+ {
+ viewType = enableRichView ? viewType : null;
+
+ return _libraryManager.GetShadowView(parent, viewType, sortName, null, cancellationToken);
+ }
+
public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
{
var user = _userManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
index a4c43af5d..26cde925e 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Library.Validators
{
@@ -29,17 +31,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
- public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
+ public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_logger = logger;
_config = config;
+ _fileSystem = fileSystem;
}
private bool DownloadMetadata(PersonInfo i, PeopleMetadataOptions options)
@@ -120,15 +124,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
var item = _libraryManager.GetPerson(person.Key);
validIds.Add(item.Id);
-
- var options = new MetadataRefreshOptions
+
+ var options = new MetadataRefreshOptions(_fileSystem)
{
- MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly,
- ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly
+ MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly,
+ ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly
};
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
catch (Exception ex)
{
_logger.ErrorException("Error validating IBN entry {0}", ex, person);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
index f205da70d..24d38a63e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs
@@ -39,58 +39,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var imageResponse = new DynamicImageResponse();
- if (!string.IsNullOrEmpty(liveTvItem.ProviderImagePath))
- {
- imageResponse.Path = liveTvItem.ProviderImagePath;
- imageResponse.HasImage = true;
- }
- else if (!string.IsNullOrEmpty(liveTvItem.ProviderImageUrl))
- {
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = liveTvItem.ProviderImageUrl,
-
- // Some image hosts require a user agent to be specified.
- UserAgent = "Emby Server/" + _appHost.ApplicationVersion
- };
+ var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
- var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
-
- var contentType = response.ContentType;
-
- if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Content;
- imageResponse.SetFormatFromMimeType(contentType);
- }
- else
- {
- _logger.Error("Provider did not return an image content type.");
- }
- }
- else if (liveTvItem.HasProviderImage ?? true)
+ if (service != null)
{
- var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
-
- if (service != null)
+ try
{
- try
- {
- var response = await service.GetChannelImageAsync(liveTvItem.ExternalId, cancellationToken).ConfigureAwait(false);
+ var response = await service.GetChannelImageAsync(liveTvItem.ExternalId, cancellationToken).ConfigureAwait(false);
- if (response != null)
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Stream;
- imageResponse.Format = response.Format;
- }
- }
- catch (NotImplementedException)
+ if (response != null)
{
+ imageResponse.HasImage = true;
+ imageResponse.Stream = response.Stream;
+ imageResponse.Format = response.Format;
}
}
+ catch (NotImplementedException)
+ {
+ }
}
return imageResponse;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index b89d8a8d1..2ac06cda8 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -8,7 +8,9 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@@ -24,6 +26,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -47,10 +51,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly IFileOrganizationService _organizationService;
+ private readonly IMediaEncoder _mediaEncoder;
public static EmbyTV Current;
- 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)
+ 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)
{
Current = this;
@@ -64,12 +69,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_libraryMonitor = libraryMonitor;
_providerManager = providerManager;
_organizationService = organizationService;
+ _mediaEncoder = mediaEncoder;
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
- _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
- _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+ _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"));
_timerProvider.TimerFired += _timerProvider_TimerFired;
}
@@ -126,6 +132,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return status;
}
+ public async Task RefreshSeriesTimers(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var timers = await GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+
+ List<ChannelInfo> channels = null;
+
+ foreach (var timer in timers)
+ {
+ List<ProgramInfo> epgData;
+
+ if (timer.RecordAnyChannel)
+ {
+ if (channels == null)
+ {
+ channels = (await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false)).ToList();
+ }
+ var channelIds = channels.Select(i => i.Id).ToList();
+ epgData = GetEpgDataForChannels(channelIds);
+ }
+ else
+ {
+ epgData = GetEpgDataForChannel(timer.ChannelId);
+ }
+ await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
+ }
+ }
+
private List<ChannelInfo> _channelCache = null;
private async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken)
{
@@ -235,7 +268,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
- File.Delete(remove.Path);
+ _fileSystem.DeleteFile(remove.Path);
}
catch (DirectoryNotFoundException)
{
@@ -247,6 +280,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
_recordingProvider.Delete(remove);
}
+ else
+ {
+ throw new ResourceNotFoundException("Recording not found: " + recordingId);
+ }
}
public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken)
@@ -327,9 +364,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new NotImplementedException();
}
- public Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
+ public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{
- return Task.FromResult((IEnumerable<RecordingInfo>)_recordingProvider.GetAll());
+ 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;
}
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@@ -364,39 +423,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return Task.FromResult((IEnumerable<SeriesTimerInfo>)_seriesTimerProvider.GetAll());
}
- public async Task RefreshSeriesTimers(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var timers = await GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
-
- List<ChannelInfo> channels = null;
-
- foreach (var timer in timers)
- {
- List<ProgramInfo> epgData;
-
- if (timer.RecordAnyChannel)
- {
- if (channels == null)
- {
- channels = (await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false)).ToList();
- }
- var channelIds = channels.Select(i => i.Id).ToList();
- epgData = GetEpgDataForChannels(channelIds);
- }
- else
- {
- epgData = GetEpgDataForChannel(timer.ChannelId);
- }
- await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
- }
- }
-
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
try
{
return await GetProgramsAsyncInternal(channelId, startDateUtc, endDateUtc, cancellationToken).ConfigureAwait(false);
}
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
catch (Exception ex)
{
_logger.ErrorException("Error getting programs", ex);
@@ -411,7 +447,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
foreach (var provider in GetListingProviders())
{
- var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, startDateUtc, endDateUtc, cancellationToken)
+ var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
var list = programs.ToList();
@@ -457,20 +493,36 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
- MediaSourceInfo mediaSourceInfo = null;
try
{
- mediaSourceInfo = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+ var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+
+ result.Item2.Release();
+
+ return result.Item1;
}
catch (Exception e)
{
_logger.ErrorException("Error getting channel stream", e);
}
+ }
+
+ throw new ApplicationException("Tuner not found.");
+ }
+
+ private async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
+ {
+ _logger.Info("Streaming Channel " + channelId);
- if (mediaSourceInfo != null)
+ foreach (var hostInstance in _liveTvManager.TunerHosts)
+ {
+ try
{
- mediaSourceInfo.Id = Guid.NewGuid().ToString("N");
- return mediaSourceInfo;
+ return await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Error getting channel stream", e);
}
}
@@ -527,11 +579,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
+ var recordingEndDate = timer.EndDate.AddSeconds(timer.PostPaddingSeconds);
+
+ if (recordingEndDate <= DateTime.UtcNow)
+ {
+ _logger.Warn("Recording timer fired for timer {0}, Id: {1}, but the program has already ended.", timer.Name, timer.Id);
+ return;
+ }
+
var cancellationTokenSource = new CancellationTokenSource();
if (_activeRecordings.TryAdd(timer.Id, cancellationTokenSource))
{
- await RecordStream(timer, cancellationTokenSource.Token).ConfigureAwait(false);
+ await RecordStream(timer, recordingEndDate, cancellationTokenSource.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
@@ -544,58 +604,62 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- private async Task RecordStream(TimerInfo timer, CancellationToken cancellationToken)
+ private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, CancellationToken cancellationToken)
{
if (timer == null)
{
throw new ArgumentNullException("timer");
}
- var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None);
- var duration = (timer.EndDate - DateTime.UtcNow).Add(TimeSpan.FromSeconds(timer.PostPaddingSeconds));
-
- HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
+ if (string.IsNullOrWhiteSpace(timer.ProgramId))
{
- Url = mediaStreamInfo.Path
- };
+ throw new InvalidOperationException("timer.ProgramId is null. Cannot record.");
+ }
var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId);
+
+ if (info == null)
+ {
+ 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));
+ recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name).Trim());
}
else if (info.IsSeries)
{
- recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name));
+ recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name).Trim());
}
else if (info.IsKids)
{
- recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name));
+ recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name).Trim());
}
else if (info.IsSports)
{
- recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name));
+ recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name).Trim());
}
else
{
- recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name));
+ recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name).Trim());
}
- var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts";
+ var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts";
recordPath = Path.Combine(recordPath, recordingFileName);
- Directory.CreateDirectory(Path.GetDirectoryName(recordPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
- var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase));
+ 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 = Guid.NewGuid().ToString("N"),
+ Id = recordingId,
StartDate = info.StartDate,
EndDate = info.EndDate,
Genres = info.Genres,
@@ -611,7 +675,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
Name = info.Name,
EpisodeTitle = info.EpisodeTitle,
ProgramId = info.Id,
- HasImage = info.HasImage,
ImagePath = info.ImagePath,
ImageUrl = info.ImageUrl,
OriginalAirDate = info.OriginalAirDate,
@@ -624,30 +687,58 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_recordingProvider.Add(recording);
}
- recording.Path = recordPath;
- recording.Status = RecordingStatus.InProgress;
- recording.DateLastUpdated = DateTime.UtcNow;
- _recordingProvider.Update(recording);
-
- _logger.Info("Beginning recording.");
-
try
{
- httpRequestOptions.BufferContent = false;
- var durationToken = new CancellationTokenSource(duration);
- var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
- httpRequestOptions.CancellationToken = linkedToken;
- _logger.Info("Writing file to path: " + recordPath);
- using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
+ var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None);
+ var mediaStreamInfo = result.Item1;
+ var isResourceOpen = true;
+
+ // Unfortunately due to the semaphore we have to have a nested try/finally
+ try
+ {
+ // 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;
+
+ HttpRequestOptions httpRequestOptions = new HttpRequestOptions()
+ {
+ Url = mediaStreamInfo.Path
+ };
+
+ recording.Path = recordPath;
+ recording.Status = RecordingStatus.InProgress;
+ recording.DateLastUpdated = DateTime.UtcNow;
+ _recordingProvider.Update(recording);
+
+ _logger.Info("Beginning recording.");
+
+ httpRequestOptions.BufferContent = false;
+ var durationToken = new CancellationTokenSource(duration);
+ var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ httpRequestOptions.CancellationToken = linkedToken;
+ _logger.Info("Writing file to path: " + recordPath);
+ using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
+ {
+ using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ result.Item2.Release();
+ isResourceOpen = false;
+
+ await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
+ }
+ }
+
+ recording.Status = RecordingStatus.Completed;
+ _logger.Info("Recording completed");
+ }
+ finally
{
- using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ if (isResourceOpen)
{
- await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
+ result.Item2.Release();
}
}
-
- recording.Status = RecordingStatus.Completed;
- _logger.Info("Recording completed");
}
catch (OperationCanceledException)
{
@@ -794,14 +885,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private string GetChannelEpgCachePath(string channelId)
{
- return Path.Combine(DataPath, "epg", channelId + ".json");
+ return Path.Combine(_config.CommonApplicationPaths.CachePath, "embytvepg", channelId + ".json");
}
private readonly object _epgLock = new object();
private void SaveEpgDataForChannel(string channelId, List<ProgramInfo> epgData)
{
var path = GetChannelEpgCachePath(channelId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_epgLock)
{
_jsonSerializer.SerializeToFile(epgData, path);
@@ -848,4 +939,4 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
});
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 75dec5f97..d89c1c0cb 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,13 +18,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
protected readonly ILogger Logger;
private readonly string _dataPath;
protected readonly Func<T, T, bool> EqualityComparer;
+ private readonly IFileSystem _fileSystem;
- public ItemDataProvider(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
+ public ItemDataProvider(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
{
Logger = logger;
_dataPath = dataPath;
EqualityComparer = equalityComparer;
_jsonSerializer = jsonSerializer;
+ _fileSystem = fileSystem;
}
public IReadOnlyList<T> GetAll()
@@ -69,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void UpdateList(List<T> newList)
{
var file = _dataPath + ".json";
- Directory.CreateDirectory(Path.GetDirectoryName(file));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(file));
lock (_fileDataLock)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 5b83d63b1..3ee808bb5 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -67,10 +67,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- else if (info.ProductionYear != null)
+ else if (info.IsMovie && info.ProductionYear != null)
{
name += " (" + info.ProductionYear + ")";
}
+ else
+ {
+ name += " " + info.StartDate.ToString("yyyy-MM-dd");
+ }
return name;
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
index eab278eb4..6d88c7c0a 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
@@ -2,13 +2,15 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class SeriesTimerManager : ItemDataProvider<SeriesTimerInfo>
{
- public SeriesTimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public SeriesTimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 3ae38f382..94ad5e5ce 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -7,6 +7,8 @@ using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,8 +18,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs
index e446ff469..ae441b44e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs
@@ -31,7 +31,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby
get { return "emby"; }
}
- public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
return GetListingsProvider(info.Country).GetProgramsAsync(info, channelNumber, startDateUtc, endDateUtc, cancellationToken);
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 2efa91137..434578718 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return dates;
}
- public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
List<ProgramInfo> programsInfo = new List<ProgramInfo>();
@@ -82,19 +82,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
UserAgent = UserAgent,
CancellationToken = cancellationToken,
// The data can be large so give it some extra time
- TimeoutMs = 60000
+ TimeoutMs = 60000,
+ LogErrorResponseBody = true
};
httpOptions.RequestHeaders["token"] = token;
var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
- ScheduleDirect.Station station = null;
+ ScheduleDirect.Station station = GetStation(channelNumber, channelName);
- if (!_channelPair.TryGetValue(channelNumber, out station))
+ if (station == null)
{
+ _logger.Info("No Schedules Direct Station found for channel {0} with name {1}", channelNumber, channelName);
return programsInfo;
}
+
string stationID = station.stationID;
_logger.Info("Channel Station ID is: " + stationID);
@@ -122,7 +125,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
Url = ApiUrl + "/programs",
UserAgent = UserAgent,
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
httpOptions.RequestHeaders["token"] = token;
@@ -152,10 +156,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
// schedule.programID + " which says it has images? " +
// programDict[schedule.programID].hasImageArtwork);
- var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
- if (imageIndex > -1)
+ if (images != null)
{
- programDict[schedule.programID].images = GetProgramLogo(ApiUrl, images[imageIndex]);
+ var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10));
+ if (imageIndex > -1)
+ {
+ programDict[schedule.programID].images = GetProgramLogo(ApiUrl, images[imageIndex]);
+ }
}
programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID]));
@@ -167,6 +174,30 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return programsInfo;
}
+ private ScheduleDirect.Station GetStation(string channelNumber, string channelName)
+ {
+ ScheduleDirect.Station station;
+
+ if (_channelPair.TryGetValue(channelNumber, out station))
+ {
+ return station;
+ }
+
+ if (string.IsNullOrWhiteSpace(channelName))
+ {
+ return null;
+ }
+
+ channelName = NormalizeName(channelName);
+
+ return _channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
+ }
+
+ private string NormalizeName(string value)
+ {
+ return value.Replace(" ", string.Empty).Replace("-", string.Empty);
+ }
+
public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels,
CancellationToken cancellationToken)
{
@@ -188,7 +219,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
Url = ApiUrl + "/lineups/" + info.ListingsId,
UserAgent = UserAgent,
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
httpOptions.RequestHeaders["token"] = token;
@@ -200,34 +232,42 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
_logger.Info("Mapping Stations to Channel");
foreach (ScheduleDirect.Map map in root.map)
{
- var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0');
- _logger.Debug("Found channel: " + channel + " in Schedules Direct");
- var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID);
+ var channelNumber = map.logicalChannelNumber;
- if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null)
+ if (string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channelNumber = map.channel;
+ }
+ if (string.IsNullOrWhiteSpace(channelNumber))
{
- _channelPair.TryAdd(channel, schChannel);
+ channelNumber = (map.atscMajor + "." + map.atscMinor);
}
+ channelNumber = channelNumber.TrimStart('0');
+
+ _logger.Debug("Found channel: " + channelNumber + " in Schedules Direct");
+ var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID);
+
+ _channelPair.TryAdd(channelNumber, schChannel);
}
- _logger.Info("Added " + _channelPair.Count() + " channels to the dictionary");
+ _logger.Info("Added " + _channelPair.Count + " channels to the dictionary");
foreach (ChannelInfo channel in channels)
{
- // Helper.logger.Info("Modifyin channel " + channel.Number);
- if (_channelPair.ContainsKey(channel.Number))
+ var station = GetStation(channel.Number, channel.Name);
+
+ if (station != null)
{
- if (_channelPair[channel.Number].logo != null)
+ if (station.logo != null)
{
- channel.ImageUrl = _channelPair[channel.Number].logo.URL;
+ channel.ImageUrl = station.logo.URL;
channel.HasImage = true;
}
- string channelName = _channelPair[channel.Number].name;
+ string channelName = station.name;
channel.Name = channelName;
}
else
{
- _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " +
- channel.Name);
+ _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + channel.Name);
}
}
}
@@ -293,7 +333,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
IsRepeat = repeat,
IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1,
ImageUrl = imageUrl,
- HasImage = details.hasImageArtwork,
IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase),
IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1,
IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1,
@@ -362,13 +401,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
private DateTime GetDate(string value)
{
- return DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
- CultureInfo.InvariantCulture);
+ var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture);
+
+ if (date.Kind != DateTimeKind.Utc)
+ {
+ date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
+ }
+ return date;
}
private string GetProgramLogo(string apiUrl, ScheduleDirect.ShowImages images)
{
- string url = "";
+ string url = null;
if (images.data != null)
{
var smallImages = images.data.Where(i => i.size == "Sm").ToList();
@@ -381,13 +425,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
logoIndex = 0;
}
- if (images.data[logoIndex].uri.Contains("http"))
- {
- url = images.data[logoIndex].uri;
- }
- else
+ var uri = images.data[logoIndex].uri;
+
+ if (!string.IsNullOrWhiteSpace(uri))
{
- url = apiUrl + "/image/" + images.data[logoIndex].uri;
+ if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ url = uri;
+ }
+ else
+ {
+ url = apiUrl + "/image/" + uri;
+ }
}
//_logger.Debug("URL for image is : " + url);
}
@@ -413,7 +462,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
Url = ApiUrl + "/metadata/programs",
UserAgent = UserAgent,
CancellationToken = cancellationToken,
- RequestContent = imageIdString
+ RequestContent = imageIdString,
+ LogErrorResponseBody = true
};
List<ScheduleDirect.ShowImages> images;
using (var innerResponse2 = await _httpClient.Post(httpOptions))
@@ -440,7 +490,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location,
UserAgent = UserAgent,
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
options.RequestHeaders["token"] = token;
@@ -557,7 +608,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
Url = ApiUrl + "/token",
UserAgent = UserAgent,
RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}",
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
//_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
@@ -595,7 +647,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
Url = ApiUrl + "/lineups/" + info.ListingsId,
UserAgent = UserAgent,
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
httpOptions.RequestHeaders["token"] = token;
@@ -635,7 +688,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
Url = ApiUrl + "/lineups",
UserAgent = UserAgent,
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ LogErrorResponseBody = true
};
options.RequestHeaders["token"] = token;
@@ -736,6 +790,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
public string stationID { get; set; }
public string channel { get; set; }
+ public string logicalChannelNumber { get; set; }
public int uhfVhf { get; set; }
public int atscMajor { get; set; }
public int atscMinor { get; set; }
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
index de107ced8..ac316f9a1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
get { return "xmltv"; }
}
- public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ public Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 7a26bf87c..edfca0d6c 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -29,6 +29,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.LiveTv
{
@@ -553,8 +554,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
isNew = true;
}
- item.ChannelType = channelInfo.ChannelType;
+ if (!string.Equals(channelInfo.Id, item.ExternalId))
+ {
+ isNew = true;
+ }
item.ExternalId = channelInfo.Id;
+
+ item.ChannelType = channelInfo.ChannelType;
item.ServiceName = serviceName;
item.Number = channelInfo.Number;
@@ -571,16 +577,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv
// replaceImages.Add(ImageType.Primary);
//}
- item.ProviderImageUrl = channelInfo.ImageUrl;
- item.HasProviderImage = channelInfo.HasImage;
- item.ProviderImagePath = channelInfo.ImagePath;
+ if (!string.IsNullOrWhiteSpace(channelInfo.ImagePath))
+ {
+ item.SetImagePath(ImageType.Primary, channelInfo.ImagePath);
+ }
+ else if (!string.IsNullOrWhiteSpace(channelInfo.ImageUrl))
+ {
+ item.SetImagePath(ImageType.Primary, channelInfo.ImageUrl);
+ }
if (string.IsNullOrEmpty(item.Name))
{
item.Name = channelInfo.Name;
}
- await item.RefreshMetadata(new MetadataRefreshOptions
+ await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew,
ReplaceImages = replaceImages.Distinct().ToList()
@@ -606,7 +617,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
Id = id,
DateCreated = DateTime.UtcNow,
DateModified = DateTime.UtcNow,
- Etag = info.Etag
+ ExternalEtag = info.Etag
};
}
@@ -620,7 +631,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.EpisodeTitle = info.EpisodeTitle;
item.ExternalId = info.Id;
item.Genres = info.Genres;
- item.HasProviderImage = info.HasImage;
item.IsHD = info.IsHD;
item.IsKids = info.IsKids;
item.IsLive = info.IsLive;
@@ -633,33 +643,46 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.Name = info.Name;
item.OfficialRating = item.OfficialRating ?? info.OfficialRating;
item.Overview = item.Overview ?? info.Overview;
- item.OriginalAirDate = info.OriginalAirDate;
- item.ProviderImagePath = info.ImagePath;
- item.ProviderImageUrl = info.ImageUrl;
item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks;
item.StartDate = info.StartDate;
item.HomePageUrl = info.HomePageUrl;
item.ProductionYear = info.ProductionYear;
- item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
+ item.PremiereDate = info.OriginalAirDate;
item.IndexNumber = info.EpisodeNumber;
item.ParentIndexNumber = info.SeasonNumber;
+ if (!string.IsNullOrWhiteSpace(info.ImagePath))
+ {
+ item.SetImagePath(ImageType.Primary, info.ImagePath);
+ }
+ else if (!string.IsNullOrWhiteSpace(info.ImageUrl))
+ {
+ item.SetImagePath(ImageType.Primary, info.ImageUrl);
+ }
+
if (isNew)
{
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
+ else if (string.IsNullOrWhiteSpace(info.Etag))
+ {
+ await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
+ }
else
{
- if (string.IsNullOrWhiteSpace(info.Etag) || !string.Equals(info.Etag, item.Etag, StringComparison.OrdinalIgnoreCase))
+ // Increment this whenver some internal change deems it necessary
+ var etag = info.Etag + "4";
+
+ if (!string.Equals(etag, item.ExternalEtag, StringComparison.OrdinalIgnoreCase))
{
- item.Etag = info.Etag;
+ item.ExternalEtag = etag;
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem));
return item;
}
@@ -705,18 +728,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.Overview = info.Overview;
item.EndDate = info.EndDate;
item.Genres = info.Genres;
+ item.PremiereDate = info.OriginalAirDate;
var recording = (ILiveTvRecording)item;
recording.ExternalId = info.Id;
- recording.ProgramId = _tvDtoService.GetInternalProgramId(serviceName, info.ProgramId).ToString("N");
recording.Audio = info.Audio;
- recording.ChannelType = info.ChannelType;
recording.EndDate = info.EndDate;
recording.EpisodeTitle = info.EpisodeTitle;
- recording.ProviderImagePath = info.ImagePath;
- recording.ProviderImageUrl = info.ImageUrl;
recording.IsHD = info.IsHD;
recording.IsKids = info.IsKids;
recording.IsLive = info.IsLive;
@@ -726,40 +746,57 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recording.IsRepeat = info.IsRepeat;
recording.IsSeries = info.IsSeries;
recording.IsSports = info.IsSports;
- recording.OriginalAirDate = info.OriginalAirDate;
recording.SeriesTimerId = info.SeriesTimerId;
recording.StartDate = info.StartDate;
+
+ if (!string.IsNullOrWhiteSpace(info.ImagePath))
+ {
+ item.SetImagePath(ImageType.Primary, info.ImagePath);
+ }
+ else if (!string.IsNullOrWhiteSpace(info.ImageUrl))
+ {
+ item.SetImagePath(ImageType.Primary, info.ImageUrl);
+ }
+
+ var statusChanged = info.Status != recording.Status;
+
recording.Status = info.Status;
recording.ServiceName = serviceName;
- var originalPath = item.Path;
+ var pathChanged = false;
if (!string.IsNullOrEmpty(info.Path))
{
- item.Path = info.Path;
- var fileInfo = new FileInfo(info.Path);
+ pathChanged = !string.Equals(item.Path, info.Path);
+ var fileInfo = _fileSystem.GetFileInfo(info.Path);
recording.DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo);
recording.DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo);
+ item.Path = info.Path;
}
else if (!string.IsNullOrEmpty(info.Url))
{
+ pathChanged = !string.Equals(item.Path, info.Url);
item.Path = info.Url;
}
- var pathChanged = !string.Equals(originalPath, item.Path);
+ var metadataRefreshMode = MetadataRefreshMode.Default;
if (isNew)
{
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
- else if (pathChanged || info.DateLastUpdated > recording.DateLastSaved)
+ else if (pathChanged || info.DateLastUpdated > recording.DateLastSaved || statusChanged)
{
+ metadataRefreshMode = MetadataRefreshMode.FullRefresh;
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
+ {
+ MetadataRefreshMode = metadataRefreshMode
+ });
return item.Id;
}
@@ -1163,6 +1200,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
foreach (var program in channelPrograms)
{
var programItem = await GetProgram(program, channelId, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false);
+
programs.Add(programItem.Id);
}
}
@@ -1200,6 +1238,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
cancellationToken.ThrowIfCancellationRequested();
+ if (itemId == Guid.Empty)
+ {
+ // Somehow some invalid data got into the db. It probably predates the boundary checking
+ continue;
+ }
+
if (!currentIdList.Contains(itemId))
{
var item = _libraryManager.GetItemById(itemId);
@@ -1286,7 +1330,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false);
- CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+ await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new Progress<double>(), cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.UtcNow;
}
@@ -1382,25 +1426,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv
};
}
- public void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null)
+ public void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, bool addChannelInfo, User user = null)
{
var program = (LiveTvProgram)item;
var service = GetService(program);
- var channel = GetInternalChannel(program.ChannelId);
-
dto.Id = _tvDtoService.GetInternalProgramId(service.Name, program.ExternalId).ToString("N");
dto.StartDate = program.StartDate;
- dto.IsRepeat = program.IsRepeat;
dto.EpisodeTitle = program.EpisodeTitle;
- dto.ChannelType = program.ChannelType;
dto.Audio = program.Audio;
if (program.IsHD.HasValue && program.IsHD.Value)
{
dto.IsHD = program.IsHD;
}
+ if (program.IsRepeat)
+ {
+ dto.IsRepeat = program.IsRepeat;
+ }
if (program.IsMovie)
{
dto.IsMovie = program.IsMovie;
@@ -1430,15 +1474,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.IsPremiere = program.IsPremiere;
}
- dto.OriginalAirDate = program.OriginalAirDate;
-
- if (channel != null)
+ if (addChannelInfo)
{
- dto.ChannelName = channel.Name;
+ var channel = GetInternalChannel(program.ChannelId);
- if (!string.IsNullOrEmpty(channel.PrimaryImagePath))
+ if (channel != null)
{
- dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
+ dto.ChannelName = channel.Name;
+
+ if (channel.HasImage(ImageType.Primary))
+ {
+ dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
+ }
}
}
}
@@ -1461,7 +1508,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.RecordingStatus = info.Status;
dto.IsRepeat = info.IsRepeat;
dto.EpisodeTitle = info.EpisodeTitle;
- dto.ChannelType = info.ChannelType;
dto.Audio = info.Audio;
dto.IsHD = info.IsHD;
dto.IsMovie = info.IsMovie;
@@ -1471,7 +1517,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.IsNews = info.IsNews;
dto.IsKids = info.IsKids;
dto.IsPremiere = info.IsPremiere;
- dto.OriginalAirDate = info.OriginalAirDate;
dto.CanDelete = user == null
? recording.CanDelete()
@@ -1499,13 +1544,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.CompletionPercentage = pct;
}
- dto.ProgramId = info.ProgramId;
-
if (channel != null)
{
dto.ChannelName = channel.Name;
- if (!string.IsNullOrEmpty(channel.PrimaryImagePath))
+ if (channel.HasImage(ImageType.Primary))
{
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
}
@@ -1601,7 +1644,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(recording.ServiceName);
- await service.DeleteRecordingAsync(recording.ExternalId, CancellationToken.None).ConfigureAwait(false);
+ try
+ {
+ await service.DeleteRecordingAsync(recording.ExternalId, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (ResourceNotFoundException)
+ {
+
+ }
+
+ await _libraryManager.DeleteItem((BaseItem)recording).ConfigureAwait(false);
+
_lastRecordingRefreshTime = DateTime.MinValue;
}
@@ -1787,7 +1840,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
EndDate = program.EndDate ?? DateTime.MinValue,
EpisodeTitle = program.EpisodeTitle,
Genres = program.Genres,
- HasImage = program.HasProviderImage,
Id = program.ExternalId,
IsHD = program.IsHD,
IsKids = program.IsKids,
@@ -1801,8 +1853,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
OriginalAirDate = program.PremiereDate,
Overview = program.Overview,
StartDate = program.StartDate,
- ImagePath = program.ProviderImagePath,
- ImageUrl = program.ProviderImageUrl,
+ //ImagePath = program.ExternalImagePath,
Name = program.Name,
OfficialRating = program.OfficialRating
};
@@ -2352,4 +2403,4 @@ namespace MediaBrowser.Server.Implementations.LiveTv
});
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
index 134e24ef0..ab8ec720b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
@@ -1,9 +1,7 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -15,14 +13,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public class ProgramImageProvider : IDynamicImageProvider, IHasItemChangeMonitor, IHasOrder
{
private readonly ILiveTvManager _liveTvManager;
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
- public ProgramImageProvider(ILiveTvManager liveTvManager, IHttpClient httpClient, ILogger logger)
+ public ProgramImageProvider(ILiveTvManager liveTvManager)
{
_liveTvManager = liveTvManager;
- _httpClient = httpClient;
- _logger = logger;
}
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
@@ -36,55 +30,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var imageResponse = new DynamicImageResponse();
- if (!string.IsNullOrEmpty(liveTvItem.ProviderImagePath))
- {
- imageResponse.Path = liveTvItem.ProviderImagePath;
- imageResponse.HasImage = true;
- }
- else if (!string.IsNullOrEmpty(liveTvItem.ProviderImageUrl))
- {
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = liveTvItem.ProviderImageUrl
- };
+ var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
- var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
-
- if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Content;
- imageResponse.SetFormatFromMimeType(response.ContentType);
- }
- else
- {
- _logger.Error("Provider did not return an image content type.");
- }
- }
- else if (liveTvItem.HasProviderImage ?? true)
+ if (service != null)
{
- var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
-
- if (service != null)
+ try
{
- try
- {
- var channel = _liveTvManager.GetInternalChannel(liveTvItem.ChannelId);
+ var channel = _liveTvManager.GetInternalChannel(liveTvItem.ChannelId);
- var response = await service.GetProgramImageAsync(liveTvItem.ExternalId, channel.ExternalId, cancellationToken).ConfigureAwait(false);
+ var response = await service.GetProgramImageAsync(liveTvItem.ExternalId, channel.ExternalId, cancellationToken).ConfigureAwait(false);
- if (response != null)
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Stream;
- imageResponse.Format = response.Format;
- }
- }
- catch (NotImplementedException)
+ if (response != null)
{
+ imageResponse.HasImage = true;
+ imageResponse.Stream = response.Stream;
+ imageResponse.Format = response.Format;
}
}
+ catch (NotImplementedException)
+ {
+ }
}
return imageResponse;
@@ -115,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (liveTvItem != null)
{
- return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.HasProviderImage ?? true);
+ return !liveTvItem.HasImage(ImageType.Primary);
}
return false;
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
index adf1e7516..fce3223ea 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs
@@ -1,9 +1,7 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -15,14 +13,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public class RecordingImageProvider : IDynamicImageProvider, IHasItemChangeMonitor
{
private readonly ILiveTvManager _liveTvManager;
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
- public RecordingImageProvider(ILiveTvManager liveTvManager, IHttpClient httpClient, ILogger logger)
+ public RecordingImageProvider(ILiveTvManager liveTvManager)
{
_liveTvManager = liveTvManager;
- _httpClient = httpClient;
- _logger = logger;
}
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
@@ -36,53 +30,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var imageResponse = new DynamicImageResponse();
- if (!string.IsNullOrEmpty(liveTvItem.ProviderImagePath))
- {
- imageResponse.Path = liveTvItem.ProviderImagePath;
- imageResponse.HasImage = true;
- }
- else if (!string.IsNullOrEmpty(liveTvItem.ProviderImageUrl))
- {
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = liveTvItem.ProviderImageUrl
- };
+ var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
- var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
-
- if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Content;
- imageResponse.SetFormatFromMimeType(response.ContentType);
- }
- else
- {
- _logger.Error("Provider did not return an image content type.");
- }
- }
- else
+ if (service != null)
{
- var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
-
- if (service != null)
+ try
{
- try
- {
- var response = await service.GetRecordingImageAsync(liveTvItem.ExternalId, cancellationToken).ConfigureAwait(false);
+ var response = await service.GetRecordingImageAsync(liveTvItem.ExternalId, cancellationToken).ConfigureAwait(false);
- if (response != null)
- {
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Stream;
- imageResponse.Format = response.Format;
- }
- }
- catch (NotImplementedException)
+ if (response != null)
{
+ imageResponse.HasImage = true;
+ imageResponse.Stream = response.Stream;
+ imageResponse.Format = response.Format;
}
}
+ catch (NotImplementedException)
+ {
+ }
}
return imageResponse;
@@ -109,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (liveTvItem != null)
{
- return !liveTvItem.HasImage(ImageType.Primary) && (!string.IsNullOrWhiteSpace(liveTvItem.ProviderImagePath) || !string.IsNullOrWhiteSpace(liveTvItem.ProviderImageUrl));
+ return !liveTvItem.HasImage(ImageType.Primary);
}
return false;
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
index d8d91c2f9..3fb1d9661 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.LiveTv
{
- class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
+ public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
{
private readonly ILiveTvManager _liveTvManager;
private readonly IConfigurationManager _config;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 909e2bba5..d811152c2 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -9,6 +9,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
@@ -16,14 +19,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
protected readonly IConfigurationManager Config;
protected readonly ILogger Logger;
+ protected IJsonSerializer JsonSerializer;
+ protected readonly IMediaEncoder MediaEncoder;
private readonly ConcurrentDictionary<string, ChannelCache> _channelCache =
new ConcurrentDictionary<string, ChannelCache>(StringComparer.OrdinalIgnoreCase);
- public BaseTunerHost(IConfigurationManager config, ILogger logger)
+ protected BaseTunerHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder)
{
Config = config;
Logger = logger;
+ JsonSerializer = jsonSerializer;
+ MediaEncoder = mediaEncoder;
}
protected abstract Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken);
@@ -44,8 +51,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
var list = result.ToList();
+ Logger.Debug("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
- if (!string.IsNullOrWhiteSpace(key))
+ if (!string.IsNullOrWhiteSpace(key) && list.Count > 0)
{
cache = cache ?? new ChannelCache();
cache.Date = DateTime.UtcNow;
@@ -109,23 +117,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
+ try
{
- Logger.Error("Tuner is not currently available");
- continue;
- }
+ var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
- var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
+ // Prefix the id with the host Id so that we can easily find it
+ foreach (var mediaSource in mediaSources)
+ {
+ mediaSource.Id = host.Id + mediaSource.Id;
+ }
- // Prefix the id with the host Id so that we can easily find it
- foreach (var mediaSource in mediaSources)
+ return mediaSources;
+ }
+ catch (Exception ex)
{
- mediaSource.Id = host.Id + mediaSource.Id;
+ Logger.Error("Error opening tuner", ex);
}
-
- return mediaSources;
}
}
@@ -134,7 +141,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
- public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
+ public async Task<Tuple<MediaSourceInfo, SemaphoreSlim>> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
if (IsValidChannelId(channelId))
{
@@ -163,23 +170,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- // If a streamId is specified then availibility has already been checked in GetChannelStreamMediaSources
- if (string.IsNullOrWhiteSpace(streamId) && hostsWithChannel.Count > 1)
+ try
{
- if (!await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
- {
- Logger.Error("Tuner is not currently available");
- continue;
- }
- }
-
- var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
+ var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
+ var resourcePool = GetLock(host.Url);
- if (stream != null)
+ await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
+ return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
+ }
+ catch (Exception ex)
{
- return stream;
+ Logger.Error("Error opening tuner", ex);
}
}
}
@@ -187,20 +188,116 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
- protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
+ /// <summary>
+ /// The _semaphoreLocks
+ /// </summary>
+ private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>(StringComparer.OrdinalIgnoreCase);
+ /// <summary>
+ /// Gets the lock.
+ /// </summary>
+ /// <param name="url">The filename.</param>
+ /// <returns>System.Object.</returns>
+ private SemaphoreSlim GetLock(string url)
+ {
+ 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
{
- return await IsAvailableInternal(tuner, channelId, cancellationToken).ConfigureAwait(false);
+ await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
+
+ // Leave the resource locked. it will be released upstream
}
- catch (Exception ex)
+ catch (Exception)
{
- Logger.ErrorException("Error checking tuner availability", ex);
- return false;
+ // Release the resource if there's some kind of failure.
+ resourcePool.Release();
+
+ throw;
}
}
- protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
+ private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ {
+ var originalRuntime = mediaSource.RunTimeTicks;
+
+ var info = await MediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ InputPath = mediaSource.Path,
+ Protocol = mediaSource.Protocol,
+ MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
+ ExtractChapters = false
+
+ }, cancellationToken).ConfigureAwait(false);
+
+ mediaSource.Bitrate = info.Bitrate;
+ mediaSource.Container = info.Container;
+ mediaSource.Formats = info.Formats;
+ mediaSource.MediaStreams = info.MediaStreams;
+ mediaSource.RunTimeTicks = info.RunTimeTicks;
+ mediaSource.Size = info.Size;
+ mediaSource.Timestamp = info.Timestamp;
+ mediaSource.Video3DFormat = info.Video3DFormat;
+ mediaSource.VideoType = info.VideoType;
+
+ mediaSource.DefaultSubtitleStreamIndex = null;
+
+ // Null this out so that it will be treated like a live stream
+ if (!originalRuntime.HasValue)
+ {
+ mediaSource.RunTimeTicks = null;
+ }
+
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
+
+ if (audioStream == null || audioStream.Index == -1)
+ {
+ mediaSource.DefaultAudioStreamIndex = null;
+ }
+ else
+ {
+ mediaSource.DefaultAudioStreamIndex = audioStream.Index;
+ }
+
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
+ if (videoStream != null)
+ {
+ if (!videoStream.BitRate.HasValue)
+ {
+ var width = videoStream.Width ?? 1920;
+
+ if (width >= 1900)
+ {
+ videoStream.BitRate = 8000000;
+ }
+
+ else if (width >= 1260)
+ {
+ videoStream.BitRate = 3000000;
+ }
+
+ else if (width >= 700)
+ {
+ videoStream.BitRate = 1000000;
+ }
+ }
+ }
+
+ // Try to estimate this
+ if (!mediaSource.Bitrate.HasValue)
+ {
+ var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
+
+ if (total > 0)
+ {
+ mediaSource.Bitrate = total;
+ }
+ }
+ }
protected abstract bool IsValidChannelId(string channelId);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
index c74220137..92a33993a 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.Linq;
using System.Threading;
+using MediaBrowser.Common.Net;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
@@ -19,13 +20,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly ILogger _logger;
private readonly ILiveTvManager _liveTvManager;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
+ private readonly IHttpClient _httpClient;
- public HdHomerunDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager)
+ public HdHomerunDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient)
{
_deviceDiscovery = deviceDiscovery;
_config = config;
_logger = logger;
_liveTvManager = liveTvManager;
+ _httpClient = httpClient;
}
public void Run()
@@ -75,6 +78,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Strip off the port
url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/');
+ // Test it by pulling down the lineup
+ using (await _httpClient.Get(new HttpRequestOptions
+ {
+ Url = string.Format("{0}/lineup.json", url),
+ CancellationToken = CancellationToken.None
+ }))
+ {
+ }
+
await _liveTvManager.SaveTunerHost(new TunerHostInfo
{
Type = HdHomerunHost.DeviceType,
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index bccb0db0a..eebb381af 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -14,19 +14,18 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
public class HdHomerunHost : BaseTunerHost, ITunerHost
{
private readonly IHttpClient _httpClient;
- private readonly IJsonSerializer _jsonSerializer;
- public HdHomerunHost(IConfigurationManager config, ILogger logger, IHttpClient httpClient, IJsonSerializer jsonSerializer)
- : base(config, logger)
+ public HdHomerunHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient) : base(config, logger, jsonSerializer, mediaEncoder)
{
_httpClient = httpClient;
- _jsonSerializer = jsonSerializer;
}
public string Name
@@ -55,7 +54,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
};
using (var stream = await _httpClient.Get(options))
{
- var root = _jsonSerializer.DeserializeFromStream<List<Channels>>(stream);
+ var root = JsonSerializer.DeserializeFromStream<List<Channels>>(stream);
if (root != null)
{
@@ -88,7 +87,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Url = string.Format("{0}/", GetApiUrl(info, false)),
CancellationToken = cancellationToken,
CacheLength = TimeSpan.FromDays(1),
- CacheMode = CacheMode.Unconditional
+ CacheMode = CacheMode.Unconditional,
+ TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds)
}))
{
using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
@@ -103,7 +103,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- return null;
+ return model;
}
public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
@@ -113,7 +113,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
using (var stream = await _httpClient.Get(new HttpRequestOptions()
{
Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)),
- CancellationToken = cancellationToken
+ CancellationToken = cancellationToken,
+ TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds)
}))
{
var tuners = new List<LiveTvTunerInfo>();
@@ -325,11 +326,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BitRate = 128000
}
},
- RequiresOpening = false,
- RequiresClosing = false,
+ RequiresOpening = true,
+ RequiresClosing = true,
BufferMs = 1000,
Container = "ts",
- Id = profile
+ Id = profile,
+ SupportsDirectPlay = true,
+ SupportsDirectStream = true,
+ SupportsTranscoding = true
};
return mediaSource;
@@ -372,16 +376,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
protected override bool IsValidChannelId(string channelId)
{
+ if (string.IsNullOrWhiteSpace(channelId))
+ {
+ throw new ArgumentNullException("channelId");
+ }
+
return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
}
protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
- Logger.Debug("GetChannelStream: channel id: {0}. stream id: {1}", channelId, streamId ?? string.Empty);
+ Logger.Info("GetChannelStream: channel id: {0}. stream id: {1}", channelId, streamId ?? string.Empty);
if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase))
{
- return null;
+ throw new ArgumentException("Channel not found");
}
channelId = channelId.Substring(ChannelIdPrefix.Length);
@@ -395,12 +404,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false);
}
}
-
- protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false);
-
- return info.Any(i => i.Status == LiveTvTunerStatus.Available || string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 3783e4b08..afd41e3d8 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -12,14 +12,23 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost
{
- public M3UTunerHost(IConfigurationManager config, ILogger logger)
- : base(config, logger)
+ private readonly IFileSystem _fileSystem;
+ private readonly IHttpClient _httpClient;
+
+ public M3UTunerHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) : base(config, logger, jsonSerializer, mediaEncoder)
{
+ _fileSystem = fileSystem;
+ _httpClient = httpClient;
}
public override string Type
@@ -41,47 +50,48 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
string line;
// Read the file and display it line by line.
- var file = new StreamReader(url);
- var channels = new List<M3UChannel>();
+ using (var file = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false)))
+ {
+ var channels = new List<M3UChannel>();
- string channnelName = null;
- string channelNumber = null;
+ string channnelName = null;
+ string channelNumber = null;
- while ((line = file.ReadLine()) != null)
- {
- line = line.Trim();
- if (string.IsNullOrWhiteSpace(line))
+ while ((line = file.ReadLine()) != null)
{
- continue;
- }
+ line = line.Trim();
+ if (string.IsNullOrWhiteSpace(line))
+ {
+ continue;
+ }
- if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
+ if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
- if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase))
- {
- var parts = line.Split(new[] { ':' }, 2).Last().Split(new[] { ',' }, 2);
- channelNumber = parts[0];
- channnelName = parts[1];
- }
- else if (!string.IsNullOrWhiteSpace(channelNumber))
- {
- channels.Add(new M3UChannel
+ if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase))
{
- Name = channnelName,
- Number = channelNumber,
- Id = ChannelIdPrefix + urlHash + channelNumber,
- Path = line
- });
-
- channelNumber = null;
- channnelName = null;
+ var parts = line.Split(new[] { ':' }, 2).Last().Split(new[] { ',' }, 2);
+ channelNumber = parts[0];
+ channnelName = parts[1];
+ }
+ else if (!string.IsNullOrWhiteSpace(channelNumber))
+ {
+ channels.Add(new M3UChannel
+ {
+ Name = channnelName,
+ Number = channelNumber,
+ Id = ChannelIdPrefix + urlHash + channelNumber,
+ Path = line
+ });
+
+ channelNumber = null;
+ channnelName = null;
+ }
}
+ return channels;
}
- file.Close();
- return channels;
}
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@@ -119,9 +129,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
- if (!File.Exists(info.Url))
+ using (var stream = await GetListingsStream(info, CancellationToken.None).ConfigureAwait(false))
{
- throw new FileNotFoundException();
+
}
}
@@ -130,6 +140,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
}
+ private Task<Stream> GetListingsStream(TunerHostInfo info, CancellationToken cancellationToken)
+ {
+ if (info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ {
+ return _httpClient.Get(info.Url, cancellationToken);
+ }
+ return Task.FromResult(_fileSystem.OpenRead(info.Url));
+ }
+
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
var urlHash = info.Url.GetMD5().ToString("N");
@@ -190,10 +209,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
return new List<MediaSourceInfo> { };
}
-
- protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ar.json b/MediaBrowser.Server.Implementations/Localization/Core/ar.json
index 3d15d7b2e..fd47027c2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ar.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/bg-BG.json b/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
index 8854611a0..aeebd2038 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/bg-BG.json
@@ -17,7 +17,7 @@
"ValueSpecialEpisodeName": "Special - {0}",
"LabelChapterName": "Chapter {0}",
"NameSeasonNumber": "Season {0}",
- "LabelExit": "\u0418\u0437\u043b\u0435\u0437",
+ "LabelExit": "\u0418\u0437\u0445\u043e\u0434",
"LabelVisitCommunity": "\u041f\u043e\u0441\u0435\u0442\u0438 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u0442\u043e",
"LabelGithub": "Github",
"LabelApiDocumentation": "API \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f",
@@ -25,7 +25,7 @@
"LabelBrowseLibrary": "\u0420\u0430\u0437\u0433\u043b\u0435\u0434\u0430\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0442\u0430",
"LabelConfigureServer": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0439 Emby",
"LabelRestartServer": "\u0420\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0439 \u0441\u044a\u0440\u0432\u044a\u0440\u0430",
- "CategorySync": "Sync",
+ "CategorySync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437.",
"CategoryUser": "User",
"CategorySystem": "System",
"CategoryApplication": "Application",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/ca.json b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
index 35f2bafb8..46004f52c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ca.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/core.json b/MediaBrowser.Server.Implementations/Localization/Core/core.json
index 4eb66929d..5f11b9436 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/core.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/core.json
@@ -173,5 +173,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Community ratings",
+ "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/cs.json b/MediaBrowser.Server.Implementations/Localization/Core/cs.json
index ee30a6028..771e735e9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/cs.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/da.json b/MediaBrowser.Server.Implementations/Localization/Core/da.json
index 21d7e9e14..e6e4d9835 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/da.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Aldersgr\u00e6nser",
- "HeaderCommunityRatings": "Community 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/Localization/Core/de.json b/MediaBrowser.Server.Implementations/Localization/Core/de.json
index 277a224ce..1939df199 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/de.json
@@ -25,7 +25,7 @@
"LabelBrowseLibrary": "Bibliothek durchsuchen",
"LabelConfigureServer": "Konfiguriere Emby",
"LabelRestartServer": "Server neustarten",
- "CategorySync": "Synchronisieren",
+ "CategorySync": "Sync",
"CategoryUser": "Benutzer",
"CategorySystem": "System",
"CategoryApplication": "Anwendung",
@@ -172,5 +172,6 @@
"HeaderProducer": "Produzenten",
"HeaderWriter": "Autoren",
"HeaderParentalRatings": "Altersbeschr\u00e4nkung",
- "HeaderCommunityRatings": "Community Bewertungen"
+ "HeaderCommunityRatings": "Community Bewertungen",
+ "StartupEmbyServerIsLoading": "Emby Server startet, bitte versuchen Sie es gleich noch einmal."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/el.json b/MediaBrowser.Server.Implementations/Localization/Core/el.json
index 213868042..7e94f7987 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/el.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/en-GB.json b/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
index 566d2cf09..73534b08d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-GB.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/en-US.json b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
index abe203804..e444c0e93 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/en-US.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/es-AR.json b/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
index 9c1ea6cb9..8068e32a9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es-AR.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/es-MX.json b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
index 9e1030dbd..972f94100 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es-MX.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Productores",
"HeaderWriter": "Guionistas",
"HeaderParentalRatings": "Clasificaci\u00f3n Parental",
- "HeaderCommunityRatings": "Clasificaciones de la comunidad"
+ "HeaderCommunityRatings": "Clasificaciones de la comunidad",
+ "StartupEmbyServerIsLoading": "El servidor Emby esta cargando. Por favor intente de nuevo dentro de poco."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/es.json b/MediaBrowser.Server.Implementations/Localization/Core/es.json
index f93fd7219..9bf56e4af 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/es.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/fi.json b/MediaBrowser.Server.Implementations/Localization/Core/fi.json
index 5df95146c..f0ab5b0d0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/fi.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/fr.json b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
index fe76ac64e..182e89bf6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/fr.json
@@ -20,7 +20,7 @@
"LabelExit": "Quitter",
"LabelVisitCommunity": "Visiter la Communaut\u00e9",
"LabelGithub": "Github",
- "LabelApiDocumentation": "Documentation API",
+ "LabelApiDocumentation": "Documentation de l'API",
"LabelDeveloperResources": "Ressources pour d\u00e9veloppeurs",
"LabelBrowseLibrary": "Parcourir la biblioth\u00e8que",
"LabelConfigureServer": "Configurer Emby",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producteurs",
"HeaderWriter": "Auteur(e)s",
"HeaderParentalRatings": "Note parentale",
- "HeaderCommunityRatings": "Classification de la communaut\u00e9"
+ "HeaderCommunityRatings": "Classification de la communaut\u00e9",
+ "StartupEmbyServerIsLoading": "Le serveur Emby est en cours de chargement. Veuillez r\u00e9essayer dans quelques instant."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/gsw.json b/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
index 7334b24ce..736c3d18f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/gsw.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/he.json b/MediaBrowser.Server.Implementations/Localization/Core/he.json
index b3bec3f02..a66438482 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/he.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/hr.json b/MediaBrowser.Server.Implementations/Localization/Core/hr.json
index 451ff4f36..2b9d56566 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/hr.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/it.json b/MediaBrowser.Server.Implementations/Localization/Core/it.json
index 90f800634..2030ea110 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/it.json
@@ -20,8 +20,8 @@
"LabelExit": "Esci",
"LabelVisitCommunity": "Visita la Community",
"LabelGithub": "Github",
- "LabelApiDocumentation": "Documentazione sulle Api",
- "LabelDeveloperResources": "Risorse per i programmatori",
+ "LabelApiDocumentation": "Documentazione Api",
+ "LabelDeveloperResources": "Risorse programmatori",
"LabelBrowseLibrary": "Esplora la libreria",
"LabelConfigureServer": "Configura Emby",
"LabelRestartServer": "Riavvia Server",
@@ -120,36 +120,36 @@
"UserStartedPlayingItemWithValues": "{0} \u00e8 partito da {1}",
"UserStoppedPlayingItemWithValues": "{0} stoppato {1}",
"SubtitleDownloadFailureForItem": "Sottotitoli non scaricati per {0}",
- "HeaderUnidentified": "Unidentified",
- "HeaderImagePrimary": "Primary",
- "HeaderImageBackdrop": "Backdrop",
+ "HeaderUnidentified": "Non identificata",
+ "HeaderImagePrimary": "Primaria",
+ "HeaderImageBackdrop": "Sfondo",
"HeaderImageLogo": "Logo",
- "HeaderUserPrimaryImage": "User Image",
- "HeaderOverview": "Overview",
- "HeaderShortOverview": "Short Overview",
- "HeaderType": "Type",
- "HeaderSeverity": "Severity",
+ "HeaderUserPrimaryImage": "Immagine utente",
+ "HeaderOverview": "Panoramica",
+ "HeaderShortOverview": "breve panoramica",
+ "HeaderType": "Tipo",
+ "HeaderSeverity": "gravit\u00e0",
"HeaderUser": "Utente",
"HeaderName": "Nome",
"HeaderDate": "Data",
- "HeaderPremiereDate": "Premiere Date",
- "HeaderDateAdded": "Date Added",
+ "HeaderPremiereDate": "Data della prima",
+ "HeaderDateAdded": "Aggiunto il",
"HeaderReleaseDate": "Data Rilascio",
"HeaderRuntime": "Durata",
- "HeaderPlayCount": "Play Count",
+ "HeaderPlayCount": "Visto N\u00b0",
"HeaderSeason": "Stagione",
"HeaderSeasonNumber": "Stagione Numero",
- "HeaderSeries": "Series:",
+ "HeaderSeries": "Serie:",
"HeaderNetwork": "Rete",
- "HeaderYear": "Year:",
- "HeaderYears": "Years:",
- "HeaderParentalRating": "Parental Rating",
+ "HeaderYear": "Anno:",
+ "HeaderYears": "Anni",
+ "HeaderParentalRating": "Valutazione parentale",
"HeaderCommunityRating": "Voto Comunit\u00e0",
"HeaderTrailers": "Trailers",
"HeaderSpecials": "Speciali",
- "HeaderGameSystems": "Game Systems",
- "HeaderPlayers": "Players:",
- "HeaderAlbumArtists": "Album Artists",
+ "HeaderGameSystems": "Sistemi di gioco",
+ "HeaderPlayers": "Giocatori",
+ "HeaderAlbumArtists": "Album Artisti",
"HeaderAlbums": "Album",
"HeaderDisc": "Disco",
"HeaderTrack": "Traccia",
@@ -162,15 +162,16 @@
"HeaderCountries": "Paesi",
"HeaderStatus": "Stato",
"HeaderTracks": "Traccia",
- "HeaderMusicArtist": "Music artist",
- "HeaderLocked": "Locked",
+ "HeaderMusicArtist": "Musica artisti",
+ "HeaderLocked": "Bloccato",
"HeaderStudios": "Studios",
- "HeaderActor": "Actors",
- "HeaderComposer": "Composers",
- "HeaderDirector": "Directors",
- "HeaderGuestStar": "Guest star",
- "HeaderProducer": "Producers",
- "HeaderWriter": "Writers",
+ "HeaderActor": "Attori",
+ "HeaderComposer": "Compositori",
+ "HeaderDirector": "Registi",
+ "HeaderGuestStar": "Personaggi famosi",
+ "HeaderProducer": "Produttori",
+ "HeaderWriter": "Sceneggiatori",
"HeaderParentalRatings": "Valutazioni genitori",
- "HeaderCommunityRatings": "Community ratings"
+ "HeaderCommunityRatings": "Valutazione Comunity",
+ "StartupEmbyServerIsLoading": "Emby server si sta avviando. Riprova tra un po"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/kk.json b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
index 7e17dea6b..be7c4c56e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/kk.json
@@ -12,7 +12,7 @@
"FolderTypeBooks": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440",
"FolderTypeTvShows": "\u0422\u0414",
"FolderTypeInherit": "\u041c\u04b1\u0440\u0430\u0493\u0430 \u0438\u0435\u043b\u0435\u043d\u0443",
- "HeaderCastCrew": "\u0422\u04af\u0441\u0456\u0440\u0443\u0433\u0435 \u049b\u0430\u0442\u044b\u0441\u049b\u0430\u043d\u0434\u0430\u0440",
+ "HeaderCastCrew": "\u0421\u043e\u043c\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440 \u043c\u0435\u043d \u0442\u04af\u0441\u0456\u0440\u0443\u0448\u0456\u043b\u0435\u0440",
"HeaderPeople": "\u0410\u0434\u0430\u043c\u0434\u0430\u0440",
"ValueSpecialEpisodeName": "\u0410\u0440\u043d\u0430\u0439\u044b - {0}",
"LabelChapterName": "{0}-\u0441\u0430\u0445\u043d\u0430",
@@ -104,7 +104,7 @@
"DeviceOnlineWithName": "{0} \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d",
"UserOnlineFromDevice": "{0} - {1} \u0430\u0440\u049b\u044b\u043b\u044b \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d",
"ProviderValue": "\u0416\u0435\u0442\u043a\u0456\u0437\u0443\u0448\u0456: {0}",
- "SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0434\u044b",
+ "SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0434\u044b",
"UserConfigurationUpdatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0434\u044b",
"UserCreatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d",
"UserPasswordChangedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437 \u04e9\u0437\u0433\u0435\u0440\u0442\u0456\u043b\u0434\u0456",
@@ -117,9 +117,9 @@
"DeviceOfflineWithName": "{0} \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
"UserLockedOutWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u049b\u04b1\u0440\u0441\u0430\u0443\u043b\u044b",
"UserOfflineFromDevice": "{0} - {1} \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
- "UserStartedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b \u0431\u0430\u0441\u0442\u0430\u043b\u0434\u044b",
- "UserStoppedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b \u0442\u043e\u049b\u0442\u0430\u043b\u0434\u044b",
- "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437",
+ "UserStartedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0434\u044b",
+ "UserStoppedPlayingItemWithValues": "{0} - {1} \u043e\u0439\u043d\u0430\u0442\u0443\u044b\u043d \u0442\u043e\u049b\u0442\u0430\u0442\u0442\u044b",
+ "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043b\u0456\u043f \u0430\u043b\u044b\u043d\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437",
"HeaderUnidentified": "\u0410\u043d\u044b\u049b\u0442\u0430\u043b\u043c\u0430\u0493\u0430\u043d",
"HeaderImagePrimary": "\u041d\u0435\u0433\u0456\u0437\u0433\u0456",
"HeaderImageBackdrop": "\u0410\u0440\u0442\u049b\u044b \u0441\u0443\u0440\u0435\u0442",
@@ -172,5 +172,6 @@
"HeaderProducer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u043b\u0435\u0440",
"HeaderWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439\u0448\u0456\u043b\u0435\u0440",
"HeaderParentalRatings": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u0442\u0430\u0440",
- "HeaderCommunityRatings": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u043b\u0430\u0440\u044b"
+ "HeaderCommunityRatings": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u043b\u0430\u0440\u044b",
+ "StartupEmbyServerIsLoading": "Emby Server \u0436\u04af\u043a\u0442\u0435\u043b\u0443\u0434\u0435. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u04e9\u043f \u04b1\u0437\u0430\u043c\u0430\u0439 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ko.json b/MediaBrowser.Server.Implementations/Localization/Core/ko.json
index 8bc5b5672..6044efb62 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ko.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/ms.json b/MediaBrowser.Server.Implementations/Localization/Core/ms.json
index a85f00132..6b5c4393f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ms.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/nb.json b/MediaBrowser.Server.Implementations/Localization/Core/nb.json
index 2ab601701..f4ebe89b6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nb.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Foreldresensur",
- "HeaderCommunityRatings": "Community 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/Localization/Core/nl.json b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
index 8658518a4..b32ebefc3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/nl.json
@@ -157,7 +157,7 @@
"HeaderVideo": "Video",
"HeaderEmbeddedImage": "Ingesloten afbeelding",
"HeaderResolution": "Resolutie",
- "HeaderSubtitles": "Ondertitels",
+ "HeaderSubtitles": "Ondertiteling",
"HeaderGenres": "Genres",
"HeaderCountries": "Landen",
"HeaderStatus": "Status",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producenten",
"HeaderWriter": "Schrijvers",
"HeaderParentalRatings": "Ouderlijke toezicht",
- "HeaderCommunityRatings": "Gemeenschapswaardering"
+ "HeaderCommunityRatings": "Gemeenschapswaardering",
+ "StartupEmbyServerIsLoading": "Emby Server is aan het laden, probeer het later opnieuw."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pl.json b/MediaBrowser.Server.Implementations/Localization/Core/pl.json
index b7b0e228e..13dca8889 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pl.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/pt-BR.json b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
index e5e8afaa5..9548262c9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pt-BR.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Produtores",
"HeaderWriter": "Escritores",
"HeaderParentalRatings": "Classifica\u00e7\u00f5es Parentais",
- "HeaderCommunityRatings": "Avalia\u00e7\u00f5es da comunidade"
+ "HeaderCommunityRatings": "Avalia\u00e7\u00f5es da comunidade",
+ "StartupEmbyServerIsLoading": "O Servidor Emby est\u00e1 carregando. Por favor, tente novamente em breve."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json b/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
index 5aa832e16..c3d514c8a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/pt-PT.json
@@ -46,7 +46,7 @@
"NotificationOptionInstallationFailed": "Falha na instala\u00e7\u00e3o",
"NotificationOptionNewLibraryContent": "Adicionado novo conte\u00fado",
"NotificationOptionNewLibraryContentMultiple": "Novo conte\u00fado adicionado (m\u00faltiplo)",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
+ "NotificationOptionCameraImageUploaded": "Imagem da c\u00e2mara carregada",
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionServerRestartRequired": "\u00c9 necess\u00e1rio reiniciar o servidor",
"ViewTypePlaylists": "Playlists",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/ro.json b/MediaBrowser.Server.Implementations/Localization/Core/ro.json
index 6c945006a..a6aa9577b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ro.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ro.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/ru.json b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
index c705ddef4..f6b33e304 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/ru.json
@@ -6,13 +6,13 @@
"FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
"FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
"FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
- "FolderTypeMusicVideos": "\u041c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
- "FolderTypeHomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "FolderTypeMusicVideos": "\u041c\u0443\u0437-\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
+ "FolderTypeHomeVideos": "\u0414\u043e\u043c-\u0438\u0435 \u0432\u0438\u0434\u0435\u043e",
"FolderTypeGames": "\u0418\u0433\u0440\u044b",
"FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438",
"FolderTypeTvShows": "\u0422\u0412",
"FolderTypeInherit": "\u041d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435",
- "HeaderCastCrew": "\u0423\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0438 \u0441\u044a\u0451\u043c\u043e\u043a",
+ "HeaderCastCrew": "\u0421\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u044c \u0438 \u0441\u043d\u0438\u043c\u0430\u043b\u0438",
"HeaderPeople": "\u041b\u044e\u0434\u0438",
"ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434 - {0}",
"LabelChapterName": "\u0421\u0446\u0435\u043d\u0430 {0}",
@@ -46,10 +46,10 @@
"NotificationOptionInstallationFailed": "\u0421\u0431\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438",
"NotificationOptionNewLibraryContent": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e",
"NotificationOptionNewLibraryContentMultiple": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e (\u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e)",
- "NotificationOptionCameraImageUploaded": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f \u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u0432\u044b\u043b\u043e\u0436\u0435\u043d\u0430",
+ "NotificationOptionCameraImageUploaded": "\u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0430 \u0432\u044b\u043a\u043b\u0430\u0434\u043a\u0430 \u043e\u0442\u0441\u043d\u044f\u0442\u043e\u0433\u043e \u0441 \u043a\u0430\u043c\u0435\u0440\u044b",
"NotificationOptionUserLockedOut": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
"NotificationOptionServerRestartRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430",
- "ViewTypePlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
+ "ViewTypePlaylists": "\u041f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u044b",
"ViewTypeMovies": "\u041a\u0438\u043d\u043e",
"ViewTypeTvShows": "\u0422\u0412",
"ViewTypeGames": "\u0418\u0433\u0440\u044b",
@@ -79,9 +79,9 @@
"ViewTypeMovieFavorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435",
"ViewTypeMovieGenres": "\u0416\u0430\u043d\u0440\u044b",
"ViewTypeMusicLatest": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435",
- "ViewTypeMusicPlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
+ "ViewTypeMusicPlaylists": "\u041f\u043b\u0435\u0439-\u043b\u0438\u0441\u0442\u044b",
"ViewTypeMusicAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
- "ViewTypeMusicAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
+ "ViewTypeMusicAlbumArtists": "\u0418\u0441\u043f-\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430",
"HeaderOtherDisplaySettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f",
"ViewTypeMusicSongs": "\u041a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438",
"ViewTypeMusicFavorites": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435",
@@ -101,8 +101,8 @@
"ItemAddedWithName": "{0} (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0443)",
"ItemRemovedWithName": "{0} (\u0438\u0437\u044a\u044f\u0442\u043e \u0438\u0437 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438)",
"LabelIpAddressValue": "IP-\u0430\u0434\u0440\u0435\u0441: {0}",
- "DeviceOnlineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
- "UserOnlineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
+ "DeviceOnlineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0443\u0441\u0442-\u043d\u043e",
+ "UserOnlineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u0443\u0441\u0442-\u043d\u043e",
"ProviderValue": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a: {0}",
"SubtitlesDownloadedForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0434\u043b\u044f {0} \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0438\u0441\u044c",
"UserConfigurationUpdatedWithName": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437-\u043b\u044f {0} \u0431\u044b\u043b\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0430",
@@ -117,11 +117,11 @@
"DeviceOfflineWithName": "{0} - \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
"UserLockedOutWithName": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c {0} \u0431\u044b\u043b \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
"UserOfflineFromDevice": "{0} - \u043f\u043e\u0434\u043a\u043b. \u0441 {1} \u043f\u0440\u0435\u0440\u0432\u0430\u043d\u043e",
- "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u0437\u0430\u043f-\u043d\u043e",
- "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440-\u0438\u0435 \u00ab{1}\u00bb \u043e\u0441\u0442-\u043d\u043e",
+ "UserStartedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u0437\u0430\u043f-\u043d\u043e",
+ "UserStoppedPlayingItemWithValues": "{0} - \u0432\u043e\u0441\u043f\u0440. \u00ab{1}\u00bb \u043e\u0441\u0442-\u043d\u043e",
"SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043a {0} \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
"HeaderUnidentified": "\u041d\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d\u043e",
- "HeaderImagePrimary": "\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439",
+ "HeaderImagePrimary": "\u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439",
"HeaderImageBackdrop": "\u0417\u0430\u0434\u043d\u0438\u043a",
"HeaderImageLogo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f",
"HeaderUserPrimaryImage": "\u0420\u0438\u0441\u0443\u043d\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
@@ -133,23 +133,23 @@
"HeaderName": "\u0418\u043c\u044f (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435)",
"HeaderDate": "\u0414\u0430\u0442\u0430",
"HeaderPremiereDate": "\u0414\u0430\u0442\u0430 \u043f\u0440\u0435\u043c\u044c\u0435\u0440\u044b",
- "HeaderDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431-\u0438\u044f",
+ "HeaderDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431.",
"HeaderReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f.",
"HeaderRuntime": "\u0414\u043b\u0438\u0442.",
- "HeaderPlayCount": "\u0427\u0438\u0441\u043b\u043e \u0432\u043e\u0441\u043f\u0440-\u0438\u0439",
+ "HeaderPlayCount": "\u041a\u043e\u043b-\u0432\u043e \u0432\u043e\u0441\u043f\u0440.",
"HeaderSeason": "\u0421\u0435\u0437\u043e\u043d",
- "HeaderSeasonNumber": "\u041d\u043e\u043c\u0435\u0440 \u0441\u0435\u0437\u043e\u043d\u0430",
+ "HeaderSeasonNumber": "\u2116 \u0441\u0435\u0437\u043e\u043d\u0430",
"HeaderSeries": "\u0421\u0435\u0440\u0438\u0430\u043b:",
"HeaderNetwork": "\u0422\u0435\u043b\u0435\u0441\u0435\u0442\u044c",
"HeaderYear": "\u0413\u043e\u0434:",
"HeaderYears": "\u0413\u043e\u0434\u044b:",
- "HeaderParentalRating": "\u0412\u043e\u0437\u0440. \u043a\u0430\u0442-\u0438\u044f",
+ "HeaderParentalRating": "\u0412\u043e\u0437\u0440. \u043a\u0430\u0442.",
"HeaderCommunityRating": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0430",
"HeaderTrailers": "\u0422\u0440\u0435\u0439\u043b.",
"HeaderSpecials": "\u0421\u043f\u0435\u0446.",
"HeaderGameSystems": "\u0418\u0433\u0440. \u0441\u0438\u0441\u0442\u0435\u043c\u044b",
"HeaderPlayers": "\u0418\u0433\u0440\u043e\u043a\u0438:",
- "HeaderAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c. \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438",
+ "HeaderAlbumArtists": "\u0418\u0441\u043f-\u043b\u0438 \u0430\u043b\u044c\u0431\u043e\u043c\u0430",
"HeaderAlbums": "\u0410\u043b\u044c\u0431\u043e\u043c\u044b",
"HeaderDisc": "\u0414\u0438\u0441\u043a",
"HeaderTrack": "\u0414\u043e\u0440-\u043a\u0430",
@@ -162,7 +162,7 @@
"HeaderCountries": "\u0421\u0442\u0440\u0430\u043d\u044b",
"HeaderStatus": "\u0421\u043e\u0441\u0442-\u0438\u0435",
"HeaderTracks": "\u0414\u043e\u0440-\u043a\u0438",
- "HeaderMusicArtist": "\u041c\u0443\u0437. \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c",
+ "HeaderMusicArtist": "\u0418\u0441\u043f. \u043c\u0443\u0437\u044b\u043a\u0438",
"HeaderLocked": "\u0417\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043e",
"HeaderStudios": "\u0421\u0442\u0443\u0434\u0438\u0438",
"HeaderActor": "\u0410\u043a\u0442\u0451\u0440\u044b",
@@ -172,5 +172,6 @@
"HeaderProducer": "\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u044b",
"HeaderWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0441\u0442\u044b",
"HeaderParentalRatings": "\u0412\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f",
- "HeaderCommunityRatings": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0438"
+ "HeaderCommunityRatings": "\u041e\u0431\u0449. \u043e\u0446\u0435\u043d\u043a\u0438",
+ "StartupEmbyServerIsLoading": "Emby Server \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u0432\u0441\u043a\u043e\u0440\u0435."
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json b/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
index abe203804..e444c0e93 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/sl-SI.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/sv.json b/MediaBrowser.Server.Implementations/Localization/Core/sv.json
index 3a5a322c6..667b8e4b4 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/sv.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/tr.json b/MediaBrowser.Server.Implementations/Localization/Core/tr.json
index f127cc816..810df2665 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/tr.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/uk.json b/MediaBrowser.Server.Implementations/Localization/Core/uk.json
index ec9ca5a39..73c9b26f9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/uk.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/vi.json b/MediaBrowser.Server.Implementations/Localization/Core/vi.json
index 6e0c3ea20..75a5dbea7 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/vi.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/Core/zh-CN.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
index 54cd7e59b..a9430c0c2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-CN.json
@@ -21,9 +21,9 @@
"LabelVisitCommunity": "\u8bbf\u95ee\u793e\u533a",
"LabelGithub": "Github",
"LabelApiDocumentation": "API\u6587\u6863",
- "LabelDeveloperResources": "\u5f00\u53d1\u8d44\u6e90",
+ "LabelDeveloperResources": "\u5f00\u53d1\u8005\u8d44\u6e90",
"LabelBrowseLibrary": "\u6d4f\u89c8\u5a92\u4f53\u5e93",
- "LabelConfigureServer": "Configure Emby",
+ "LabelConfigureServer": "\u914d\u7f6eEmby",
"LabelRestartServer": "\u91cd\u542f\u670d\u52a1\u5668",
"CategorySync": "\u540c\u6b65",
"CategoryUser": "\u7528\u6237",
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "\u5bb6\u957f\u5206\u7ea7",
- "HeaderCommunityRatings": "Community 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/Localization/Core/zh-HK.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json
new file mode 100644
index 000000000..8d25a28c4
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-HK.json
@@ -0,0 +1,177 @@
+{
+ "AppDeviceValues": "App: {0}, Device: {1}",
+ "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "FolderTypeMixed": "\u6df7\u5408\u5167\u5bb9",
+ "FolderTypeMovies": "\u96fb\u5f71",
+ "FolderTypeMusic": "\u97f3\u6a02",
+ "FolderTypeAdultVideos": "\u6210\u4eba\u5f71\u7247",
+ "FolderTypePhotos": "\u76f8\u7247",
+ "FolderTypeMusicVideos": "MV",
+ "FolderTypeHomeVideos": "\u500b\u4eba\u5f71\u7247",
+ "FolderTypeGames": "\u904a\u6232",
+ "FolderTypeBooks": "\u66f8\u85c9",
+ "FolderTypeTvShows": "\u96fb\u8996\u7bc0\u76ee",
+ "FolderTypeInherit": "\u7e7c\u627f",
+ "HeaderCastCrew": "\u6f14\u54e1\u9663\u5bb9",
+ "HeaderPeople": "\u4eba\u7269",
+ "ValueSpecialEpisodeName": "Special - {0}",
+ "LabelChapterName": "Chapter {0}",
+ "NameSeasonNumber": "\u5287\u96c6\u5b63\u5ea6 {0}",
+ "LabelExit": "\u96e2\u958b",
+ "LabelVisitCommunity": "\u8a2a\u554f\u8a0e\u8ad6\u5340",
+ "LabelGithub": "Github",
+ "LabelApiDocumentation": "Api \u6587\u4ef6",
+ "LabelDeveloperResources": "\u958b\u767c\u8005\u8cc7\u6e90",
+ "LabelBrowseLibrary": "\u700f\u89bd\u8cc7\u6599\u5eab",
+ "LabelConfigureServer": "\u8a2d\u7f6e Emby",
+ "LabelRestartServer": "\u91cd\u65b0\u555f\u52d5\u4f3a\u670d\u5668",
+ "CategorySync": "\u540c\u6b65",
+ "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": "\u9700\u8981\u91cd\u65b0\u555f\u52d5",
+ "ViewTypePlaylists": "Playlists",
+ "ViewTypeMovies": "Movies",
+ "ViewTypeTvShows": "TV",
+ "ViewTypeGames": "\u904a\u6232",
+ "ViewTypeMusic": "Music",
+ "ViewTypeMusicGenres": "Genres",
+ "ViewTypeMusicArtists": "Artists",
+ "ViewTypeBoxSets": "\u85cf\u54c1",
+ "ViewTypeChannels": "Channels",
+ "ViewTypeLiveTV": "Live TV",
+ "ViewTypeLiveTvNowPlaying": "Now Airing",
+ "ViewTypeLatestGames": "\u6700\u8fd1\u904a\u6232",
+ "ViewTypeRecentlyPlayedGames": "\u6700\u8fd1\u64ad\u653e",
+ "ViewTypeGameFavorites": "Favorites",
+ "ViewTypeGameSystems": "\u904a\u6232\u7cfb\u7d71",
+ "ViewTypeGameGenres": "Genres",
+ "ViewTypeTvResume": "Resume",
+ "ViewTypeTvNextUp": "Next Up",
+ "ViewTypeTvLatest": "Latest",
+ "ViewTypeTvShowSeries": "\u96fb\u8996\u5287",
+ "ViewTypeTvGenres": "Genres",
+ "ViewTypeTvFavoriteSeries": "\u6211\u7684\u6700\u611b\u96fb\u8996\u5287",
+ "ViewTypeTvFavoriteEpisodes": "\u6211\u7684\u6700\u611b\u5287\u96c6",
+ "ViewTypeMovieResume": "Resume",
+ "ViewTypeMovieLatest": "Latest",
+ "ViewTypeMovieMovies": "Movies",
+ "ViewTypeMovieCollections": "\u85cf\u54c1",
+ "ViewTypeMovieFavorites": "Favorites",
+ "ViewTypeMovieGenres": "Genres",
+ "ViewTypeMusicLatest": "Latest",
+ "ViewTypeMusicPlaylists": "Playlists",
+ "ViewTypeMusicAlbums": "Albums",
+ "ViewTypeMusicAlbumArtists": "Album Artists",
+ "HeaderOtherDisplaySettings": "Display Settings",
+ "ViewTypeMusicSongs": "\u6b4c\u66f2",
+ "ViewTypeMusicFavorites": "Favorites",
+ "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
+ "ViewTypeMusicFavoriteArtists": "Favorite Artists",
+ "ViewTypeMusicFavoriteSongs": "\u6211\u7684\u6700\u611b\u6b4c\u66f2",
+ "ViewTypeFolders": "Folders",
+ "ViewTypeLiveTvRecordingGroups": "Recordings",
+ "ViewTypeLiveTvChannels": "Channels",
+ "ScheduledTaskFailedWithName": "{0} failed",
+ "LabelRunningTimeValue": "Running time: {0}",
+ "ScheduledTaskStartedWithName": "{0} started",
+ "VersionNumber": "\u7248\u672c {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": "\u5df2\u7d93\u70ba {0} \u4e0b\u8f09\u4e86\u5b57\u5e55",
+ "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": "\u70ba {0} \u4e0b\u8f09\u5b57\u5e55\u5931\u6557",
+ "HeaderUnidentified": "Unidentified",
+ "HeaderImagePrimary": "Primary",
+ "HeaderImageBackdrop": "Backdrop",
+ "HeaderImageLogo": "Logo",
+ "HeaderUserPrimaryImage": "User Image",
+ "HeaderOverview": "Overview",
+ "HeaderShortOverview": "Short Overview",
+ "HeaderType": "Type",
+ "HeaderSeverity": "Severity",
+ "HeaderUser": "User",
+ "HeaderName": "\u540d\u7a31",
+ "HeaderDate": "\u65e5\u671f",
+ "HeaderPremiereDate": "Premiere Date",
+ "HeaderDateAdded": "Date Added",
+ "HeaderReleaseDate": "Release date",
+ "HeaderRuntime": "Runtime",
+ "HeaderPlayCount": "Play Count",
+ "HeaderSeason": "\u5287\u96c6\u5b63\u5ea6",
+ "HeaderSeasonNumber": "\u5287\u96c6\u5b63\u5ea6\u6578\u76ee",
+ "HeaderSeries": "\u96fb\u8996\u5287\uff1a",
+ "HeaderNetwork": "Network",
+ "HeaderYear": "Year:",
+ "HeaderYears": "Years:",
+ "HeaderParentalRating": "Parental Rating",
+ "HeaderCommunityRating": "Community rating",
+ "HeaderTrailers": "Trailers",
+ "HeaderSpecials": "Specials",
+ "HeaderGameSystems": "\u904a\u6232\u7cfb\u7d71",
+ "HeaderPlayers": "Players:",
+ "HeaderAlbumArtists": "Album Artists",
+ "HeaderAlbums": "Albums",
+ "HeaderDisc": "Disc",
+ "HeaderTrack": "Track",
+ "HeaderAudio": "\u97f3\u8a0a",
+ "HeaderVideo": "\u5f71\u7247",
+ "HeaderEmbeddedImage": "Embedded image",
+ "HeaderResolution": "Resolution",
+ "HeaderSubtitles": "\u5b57\u5e55",
+ "HeaderGenres": "Genres",
+ "HeaderCountries": "Countries",
+ "HeaderStatus": "\u72c0\u614b",
+ "HeaderTracks": "Tracks",
+ "HeaderMusicArtist": "\u6b4c\u624b",
+ "HeaderLocked": "Locked",
+ "HeaderStudios": "Studios",
+ "HeaderActor": "Actors",
+ "HeaderComposer": "Composers",
+ "HeaderDirector": "Directors",
+ "HeaderGuestStar": "\u7279\u7d04\u660e\u661f",
+ "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/Localization/Core/zh-TW.json b/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
index 787508176..2bcb5c132 100644
--- a/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Core/zh-TW.json
@@ -172,5 +172,6 @@
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community 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/Localization/LocalizationManager.cs b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
index 8c893c8d1..cf6eb8f9d 100644
--- a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
+++ b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
@@ -12,6 +12,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Localization
{
@@ -58,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Localization
var localizationPath = LocalizationPath;
- Directory.CreateDirectory(localizationPath);
+ _fileSystem.CreateDirectory(localizationPath);
var existingFiles = Directory.EnumerateFiles(localizationPath, "ratings-*.txt", SearchOption.TopDirectoryOnly)
.Select(Path.GetFileName)
@@ -212,7 +213,7 @@ namespace MediaBrowser.Server.Implementations.Localization
/// <returns>Dictionary{System.StringParentalRating}.</returns>
private void LoadRatings(string file)
{
- var dict = File.ReadAllLines(file).Select(i =>
+ var dict = File.ReadAllLines(file).Select(i =>
{
if (!string.IsNullOrWhiteSpace(i))
{
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index f0312cef6..99ef3f1f2 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -11,10 +11,9 @@
<AssemblyName>MediaBrowser.Server.Implementations</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProductVersion>10.0.0</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
+ <ReleaseVersion>
+ </ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -24,7 +23,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -33,7 +31,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
<DebugType>none</DebugType>
@@ -42,34 +39,28 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Interfaces.IO">
- <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
- </Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.5614.25103, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\MediaBrowser.Naming.1.0.0.37\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
</Reference>
- <Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll</HintPath>
+ <Reference Include="Interfaces.IO">
+ <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
</Reference>
- <Reference Include="MoreLinq, Version=1.1.17511.0, Culture=neutral, PublicKeyToken=384d532d7e88985d, processorArchitecture=MSIL">
+ <Reference Include="MediaBrowser.Naming, Version=1.0.5748.36038, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\morelinq.1.1.0\lib\net35\MoreLinq.dll</HintPath>
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.0.38\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
</Reference>
<Reference Include="Patterns.Logging">
<HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
- <Private>True</Private>
</Reference>
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
- <Reference Include="SocketHttpListener, Version=1.0.5634.16042, Culture=neutral, processorArchitecture=MSIL">
+ <Reference Include="SocketHttpListener, Version=1.0.5754.42244, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SocketHttpListener.1.0.0.7\lib\net45\SocketHttpListener.dll</HintPath>
+ <HintPath>..\packages\SocketHttpListener.1.0.0.10\lib\net45\SocketHttpListener.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -100,6 +91,12 @@
<Reference Include="UniversalDetector">
<HintPath>..\ThirdParty\UniversalDetector\UniversalDetector.dll</HintPath>
</Reference>
+ <Reference Include="Mono.Nat">
+ <HintPath>..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll</HintPath>
+ </Reference>
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -111,7 +108,6 @@
<Compile Include="Channels\ChannelConfigurations.cs" />
<Compile Include="Channels\ChannelDynamicMediaSourceProvider.cs" />
<Compile Include="Channels\ChannelImageProvider.cs" />
- <Compile Include="Channels\ChannelItemImageProvider.cs" />
<Compile Include="Channels\ChannelManager.cs" />
<Compile Include="Channels\ChannelPostScanTask.cs" />
<Compile Include="Channels\RefreshChannelsScheduledTask.cs" />
@@ -240,8 +236,10 @@
<Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="Logging\PatternsLogger.cs" />
<Compile Include="MediaEncoder\EncodingManager.cs" />
+ <Compile Include="Notifications\IConfigurableNotificationService.cs" />
<Compile Include="Persistence\BaseSqliteRepository.cs" />
<Compile Include="Persistence\CleanDatabaseScheduledTask.cs" />
+ <Compile Include="Persistence\MediaStreamColumns.cs" />
<Compile Include="Social\SharingManager.cs" />
<Compile Include="Social\SharingRepository.cs" />
<Compile Include="Sorting\StartDateComparer.cs" />
@@ -255,10 +253,8 @@
<Compile Include="Notifications\InternalNotificationService.cs" />
<Compile Include="Notifications\NotificationConfigurationFactory.cs" />
<Compile Include="Notifications\NotificationManager.cs" />
- <Compile Include="Persistence\SqliteChapterRepository.cs" />
<Compile Include="Persistence\SqliteExtensions.cs" />
<Compile Include="Persistence\SqliteFileOrganizationRepository.cs" />
- <Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
<Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
<Compile Include="Persistence\TypeMapper.cs" />
@@ -334,7 +330,6 @@
<Compile Include="Sync\SyncRepository.cs" />
<Compile Include="Sync\SyncConvertScheduledTask.cs" />
<Compile Include="Sync\TargetDataProvider.cs" />
- <Compile Include="Themes\AppThemeManager.cs" />
<Compile Include="TV\TVSeriesManager.cs" />
<Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
<Compile Include="Udp\UdpServer.cs" />
@@ -413,6 +408,7 @@
<EmbeddedResource Include="Localization\Core\vi.json" />
<EmbeddedResource Include="Localization\Core\zh-CN.json" />
<EmbeddedResource Include="Localization\Core\zh-TW.json" />
+ <EmbeddedResource Include="Localization\Core\zh-HK.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
index 6b99883a5..bd634ed73 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -14,6 +14,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.MediaEncoder
{
@@ -134,11 +135,11 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
var protocol = MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, protocol, null, video.PlayableStreamFileNames);
+ var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, video.PlayableStreamFileNames);
try
{
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var stream = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false))
{
@@ -194,7 +195,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
try
{
- return Directory.EnumerateFiles(path)
+ return _fileSystem.GetFilePaths(path)
.ToList();
}
catch (DirectoryNotFoundException)
diff --git a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
index 619384b6f..e8f910f81 100644
--- a/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs
@@ -16,6 +16,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.News
{
@@ -71,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.News
{
DateTime? lastUpdate = null;
- if (File.Exists(path))
+ if (_fileSystem.FileExists(path))
{
lastUpdate = _fileSystem.GetLastWriteTimeUtc(path);
}
@@ -79,7 +80,8 @@ namespace MediaBrowser.Server.Implementations.News
var requestOptions = new HttpRequestOptions
{
Url = "http://emby.media/community/index.php?/blog/rss/1-media-browser-developers-blog",
- Progress = new Progress<double>()
+ Progress = new Progress<double>(),
+ UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.42 Safari/537.36"
};
using (var stream = await _httpClient.Get(requestOptions).ConfigureAwait(false))
diff --git a/MediaBrowser.Server.Implementations/Notifications/IConfigurableNotificationService.cs b/MediaBrowser.Server.Implementations/Notifications/IConfigurableNotificationService.cs
new file mode 100644
index 000000000..5c4f400b0
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Notifications/IConfigurableNotificationService.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Notifications
+{
+ public interface IConfigurableNotificationService
+ {
+ bool IsHidden { get; }
+ bool IsEnabled(string notificationType);
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Notifications/InternalNotificationService.cs b/MediaBrowser.Server.Implementations/Notifications/InternalNotificationService.cs
index 56cb52f10..4a625f0fb 100644
--- a/MediaBrowser.Server.Implementations/Notifications/InternalNotificationService.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/InternalNotificationService.cs
@@ -3,10 +3,11 @@ using MediaBrowser.Controller.Notifications;
using MediaBrowser.Model.Notifications;
using System.Threading;
using System.Threading.Tasks;
+using System;
namespace MediaBrowser.Server.Implementations.Notifications
{
- public class InternalNotificationService : INotificationService
+ public class InternalNotificationService : INotificationService, IConfigurableNotificationService
{
private readonly INotificationsRepository _repo;
@@ -36,6 +37,24 @@ namespace MediaBrowser.Server.Implementations.Notifications
public bool IsEnabledForUser(User user)
{
+ return user.Policy.IsAdministrator;
+ }
+
+ public bool IsHidden
+ {
+ get { return true; }
+ }
+
+ public bool IsEnabled(string notificationType)
+ {
+ if (notificationType.IndexOf("playback", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ return false;
+ }
+ if (notificationType.IndexOf("newlibrarycontent", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ return false;
+ }
return true;
}
}
diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
index 1ff928cd5..f19ff8a5f 100644
--- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs
@@ -230,8 +230,19 @@ namespace MediaBrowser.Server.Implementations.Notifications
private bool IsEnabled(INotificationService service, string notificationType)
{
- return string.IsNullOrEmpty(notificationType) ||
- GetConfiguration().IsServiceEnabled(service.Name, notificationType);
+ if (string.IsNullOrEmpty(notificationType))
+ {
+ return true;
+ }
+
+ var configurable = service as IConfigurableNotificationService;
+
+ if (configurable != null)
+ {
+ return configurable.IsEnabled(notificationType);
+ }
+
+ return GetConfiguration().IsServiceEnabled(service.Name, notificationType);
}
public void AddParts(IEnumerable<INotificationService> services, IEnumerable<INotificationTypeFactory> notificationTypeFactories)
@@ -268,7 +279,13 @@ namespace MediaBrowser.Server.Implementations.Notifications
public IEnumerable<NotificationServiceInfo> GetNotificationServices()
{
- return _services.Select(i => new NotificationServiceInfo
+ return _services.Where(i =>
+ {
+ var configurable = i as IConfigurableNotificationService;
+
+ return configurable == null || !configurable.IsHidden;
+
+ }).Select(i => new NotificationServiceInfo
{
Name = i.Name,
Id = i.Name.GetMD5().ToString("N")
diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
index 15d76fb60..cac112b6c 100644
--- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
@@ -46,11 +46,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- protected virtual void DisposeInternal()
- {
-
- }
-
protected abstract void CloseConnection();
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
index 9f87483ba..60b8c00bd 100644
--- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
@@ -5,27 +5,32 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Server.Implementations.Persistence
{
- class CleanDatabaseScheduledTask : IScheduledTask
+ public class CleanDatabaseScheduledTask : IScheduledTask
{
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
+ private readonly IFileSystem _fileSystem;
- public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config)
+ public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
{
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_logger = logger;
_config = config;
+ _fileSystem = fileSystem;
}
public string Name
@@ -46,15 +51,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(.95 * p));
+ innerProgress.RegisterAction(p => progress.Report(.4 * p));
await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false);
innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(95 + (.05 * p)));
-
- //await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false);
+ innerProgress.RegisterAction(p => progress.Report(40 + (.05 * p)));
+ await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false);
+ progress.Report(45);
+ innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report(45 + (.55 * p)));
+ await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false);
progress.Report(100);
}
@@ -77,6 +85,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
cancellationToken.ThrowIfCancellationRequested();
+ if (itemId == Guid.Empty)
+ {
+ // Somehow some invalid data got into the db. It probably predates the boundary checking
+ continue;
+ }
+
var item = _libraryManager.GetItemById(itemId);
if (item != null)
@@ -147,11 +161,69 @@ namespace MediaBrowser.Server.Implementations.Persistence
progress.Report(100);
}
+ private async Task CleanDeletedItems(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var result = _itemRepo.GetItemIdsWithPath(new InternalItemsQuery
+ {
+ IsOffline = false,
+ LocationType = LocationType.FileSystem,
+ //Limit = limit,
+
+ // These have their own cleanup routines
+ ExcludeItemTypes = new[] { typeof(Person).Name, typeof(Genre).Name, typeof(MusicGenre).Name, typeof(GameGenre).Name, typeof(Studio).Name, typeof(Year).Name }
+ });
+
+ var numComplete = 0;
+ var numItems = result.Items.Length;
+
+ foreach (var item in result.Items)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var path = item.Item2;
+
+ try
+ {
+ if (_fileSystem.FileExists(path) || _fileSystem.DirectoryExists(path))
+ {
+ continue;
+ }
+
+ var libraryItem = _libraryManager.GetItemById(item.Item1);
+
+ if (Folder.IsPathOffline(path))
+ {
+ libraryItem.IsOffline = true;
+ await libraryItem.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false);
+ continue;
+ }
+
+ await _libraryManager.DeleteItem(libraryItem, new DeleteOptions
+ {
+ DeleteFileLocation = false
+ });
+ }
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in CleanDeletedItems. File {0}", ex, path);
+ }
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= numItems;
+ progress.Report(percent * 100);
+ }
+ }
+
public IEnumerable<ITaskTrigger> GetDefaultTriggers()
{
return new ITaskTrigger[]
{
- new IntervalTrigger{ Interval = TimeSpan.FromDays(1)}
+ new IntervalTrigger{ Interval = TimeSpan.FromHours(24)}
};
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
new file mode 100644
index 000000000..f54e702d6
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs
@@ -0,0 +1,219 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+ public class MediaStreamColumns
+ {
+ private readonly IDbConnection _connection;
+ private readonly ILogger _logger;
+
+ public MediaStreamColumns(IDbConnection connection, ILogger logger)
+ {
+ _connection = connection;
+ _logger = logger;
+ }
+
+ public void AddColumns()
+ {
+ AddPixelFormatColumnCommand();
+ AddBitDepthCommand();
+ AddIsAnamorphicColumn();
+ AddIsCabacColumn();
+ AddKeyFramesColumn();
+ AddRefFramesCommand();
+ }
+
+ private void AddPixelFormatColumnCommand()
+ {
+ 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, "PixelFormat", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column PixelFormat TEXT");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddBitDepthCommand()
+ {
+ 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, "BitDepth", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column BitDepth INT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddRefFramesCommand()
+ {
+ 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, "RefFrames", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column RefFrames INT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddIsCabacColumn()
+ {
+ 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, "IsCabac", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column IsCabac BIT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddKeyFramesColumn()
+ {
+ 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, "KeyFrames", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column KeyFrames TEXT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ private void AddIsAnamorphicColumn()
+ {
+ 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, "IsAnamorphic", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ var builder = new StringBuilder();
+
+ builder.AppendLine("alter table mediastreams");
+ builder.AppendLine("add column IsAnamorphic BIT NULL");
+
+ _connection.RunQueries(new[] { builder.ToString() }, _logger);
+ }
+
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
deleted file mode 100644
index 075ef4239..000000000
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
+++ /dev/null
@@ -1,304 +0,0 @@
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Persistence
-{
- public class SqliteChapterRepository
- {
- private IDbConnection _connection;
-
- private readonly ILogger _logger;
-
- private IDbCommand _deleteChaptersCommand;
- private IDbCommand _saveChapterCommand;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SqliteItemRepository" /> class.
- /// </summary>
- /// <param name="connection">The connection.</param>
- /// <param name="logManager">The log manager.</param>
- /// <exception cref="System.ArgumentNullException">appPaths
- /// or
- /// jsonSerializer</exception>
- public SqliteChapterRepository(IDbConnection connection, ILogManager logManager)
- {
- _connection = connection;
-
- _logger = logManager.GetLogger(GetType().Name);
- }
-
- /// <summary>
- /// Opens the connection to the database
- /// </summary>
- /// <returns>Task.</returns>
- public void Initialize()
- {
- string[] queries = {
-
- "create table if not exists chapters (ItemId GUID, ChapterIndex INT, StartPositionTicks BIGINT, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))",
- "create index if not exists idx_chapters on chapters(ItemId, ChapterIndex)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
- };
-
- _connection.RunQueries(queries, _logger);
-
- PrepareStatements();
- }
-
- /// <summary>
- /// The _write lock
- /// </summary>
- private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
- /// <summary>
- /// Prepares the statements.
- /// </summary>
- private void PrepareStatements()
- {
- _deleteChaptersCommand = _connection.CreateCommand();
- _deleteChaptersCommand.CommandText = "delete from chapters where ItemId=@ItemId";
- _deleteChaptersCommand.Parameters.Add(_deleteChaptersCommand, "@ItemId");
-
- _saveChapterCommand = _connection.CreateCommand();
- _saveChapterCommand.CommandText = "replace into chapters (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)";
-
- _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ItemId");
- _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ChapterIndex");
- _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@StartPositionTicks");
- _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@Name");
- _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ImagePath");
- }
-
- /// <summary>
- /// Gets chapters for an item
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>IEnumerable{ChapterInfo}.</returns>
- /// <exception cref="System.ArgumentNullException">id</exception>
- public IEnumerable<ChapterInfo> GetChapters(Guid id)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- using (var cmd = _connection.CreateCommand())
- {
- cmd.CommandText = "select StartPositionTicks,Name,ImagePath from Chapters where ItemId = @ItemId order by ChapterIndex asc";
-
- cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (reader.Read())
- {
- yield return GetChapter(reader);
- }
- }
- }
- }
-
- /// <summary>
- /// Gets a single chapter for an item
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="index">The index.</param>
- /// <returns>ChapterInfo.</returns>
- /// <exception cref="System.ArgumentNullException">id</exception>
- public ChapterInfo GetChapter(Guid id, int index)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- using (var cmd = _connection.CreateCommand())
- {
- cmd.CommandText = "select StartPositionTicks,Name,ImagePath from Chapters where ItemId = @ItemId and ChapterIndex=@ChapterIndex";
-
- cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
- cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
- {
- if (reader.Read())
- {
- return GetChapter(reader);
- }
- }
- return null;
- }
- }
-
- /// <summary>
- /// Gets the chapter.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>ChapterInfo.</returns>
- private ChapterInfo GetChapter(IDataReader reader)
- {
- var chapter = new ChapterInfo
- {
- StartPositionTicks = reader.GetInt64(0)
- };
-
- if (!reader.IsDBNull(1))
- {
- chapter.Name = reader.GetString(1);
- }
-
- if (!reader.IsDBNull(2))
- {
- chapter.ImagePath = reader.GetString(2);
- }
-
- return chapter;
- }
-
- /// <summary>
- /// Saves the chapters.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="chapters">The chapters.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException">
- /// id
- /// or
- /// chapters
- /// or
- /// cancellationToken
- /// </exception>
- public async Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- if (chapters == null)
- {
- throw new ArgumentNullException("chapters");
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- // First delete chapters
- _deleteChaptersCommand.GetParameter(0).Value = id;
-
- _deleteChaptersCommand.Transaction = transaction;
-
- _deleteChaptersCommand.ExecuteNonQuery();
-
- var index = 0;
-
- foreach (var chapter in chapters)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- _saveChapterCommand.GetParameter(0).Value = id;
- _saveChapterCommand.GetParameter(1).Value = index;
- _saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks;
- _saveChapterCommand.GetParameter(3).Value = chapter.Name;
- _saveChapterCommand.GetParameter(4).Value = chapter.ImagePath;
-
- _saveChapterCommand.Transaction = transaction;
-
- _saveChapterCommand.ExecuteNonQuery();
-
- index++;
- }
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- catch (Exception e)
- {
- _logger.ErrorException("Failed to save chapters:", e);
-
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
-
- _writeLock.Release();
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private readonly object _disposeLock = new object();
-
- /// <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)
- {
- try
- {
- lock (_disposeLock)
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error disposing database", ex);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
index f8cb6c9f4..011cbce1c 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
@@ -154,6 +154,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
return connection;
}
+ public static void Attach(IDbConnection db, string path, string alias)
+ {
+ using (var cmd = db.CreateCommand())
+ {
+ cmd.CommandText = string.Format("attach '{0}' as {1};", path, alias);
+ cmd.ExecuteNonQuery();
+ }
+ }
+
/// <summary>
/// Serializes to bytes.
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 00ebf7ea6..7fbd9ee89 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -18,6 +18,7 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Channels;
namespace MediaBrowser.Server.Implementations.Persistence
{
@@ -62,9 +63,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
private readonly string _criticReviewsPath;
- private SqliteChapterRepository _chapterRepository;
- private SqliteMediaStreamsRepository _mediaStreamsRepository;
-
private IDbCommand _deleteChildrenCommand;
private IDbCommand _saveChildrenCommand;
private IDbCommand _deleteItemCommand;
@@ -72,7 +70,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deletePeopleCommand;
private IDbCommand _savePersonCommand;
- private const int LatestSchemaVersion = 6;
+ private IDbCommand _deleteChaptersCommand;
+ private IDbCommand _saveChapterCommand;
+
+ private IDbCommand _deleteStreamsCommand;
+ private IDbCommand _saveStreamCommand;
+
+ private const int LatestSchemaVersion = 13;
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
@@ -102,16 +106,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
_criticReviewsPath = Path.Combine(_appPaths.DataPath, "critic-reviews");
_logger = logManager.GetLogger(GetType().Name);
-
- var chapterDbFile = Path.Combine(_appPaths.DataPath, "chapters.db");
- var chapterConnection = SqliteExtensions.ConnectToDb(chapterDbFile, _logger).Result;
- _chapterRepository = new SqliteChapterRepository(chapterConnection, logManager);
-
- var mediaStreamsDbFile = Path.Combine(_appPaths.DataPath, "mediainfo.db");
- var mediaStreamsConnection = SqliteExtensions.ConnectToDb(mediaStreamsDbFile, _logger).Result;
- _mediaStreamsRepository = new SqliteMediaStreamsRepository(mediaStreamsConnection, logManager);
}
+ private const string ChaptersTableName = "Chapters2";
+
/// <summary>
/// Opens the connection to the database
/// </summary>
@@ -122,6 +120,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).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, IsCabac BIT NULL, KeyFrames TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
+
string[] queries = {
"create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB)",
@@ -132,6 +133,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
"create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)",
+ "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)",
+
+ createMediaStreamsTableCommand,
+ "create index if not exists idx_mediastreams on mediastreams(ItemId, StreamIndex)",
+
//pragmas
"pragma temp_store = memory",
@@ -175,11 +182,81 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(_logger, "TypedBaseItems", "ForcedSortName", "Text");
_connection.AddColumn(_logger, "TypedBaseItems", "IsOffline", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "LocationType", "Text");
+
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsSeries", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsLive", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsNews", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsPremiere", "BIT");
+
+ _connection.AddColumn(_logger, "TypedBaseItems", "EpisodeTitle", "Text");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsRepeat", "BIT");
+
+ _connection.AddColumn(_logger, "TypedBaseItems", "PreferredMetadataLanguage", "Text");
+ _connection.AddColumn(_logger, "TypedBaseItems", "PreferredMetadataCountryCode", "Text");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsHD", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "ExternalEtag", "Text");
+ _connection.AddColumn(_logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME");
PrepareStatements();
- _mediaStreamsRepository.Initialize();
- _chapterRepository.Initialize();
+ 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");
+ if (File.Exists(mediaStreamsDbFile))
+ {
+ MigrateMediaStreams(mediaStreamsDbFile);
+ }
+ }
+
+ private void MigrateMediaStreams(string file)
+ {
+ var backupFile = file + ".bak";
+ File.Copy(file, backupFile, true);
+ SqliteExtensions.Attach(_connection, backupFile, "MediaInfoOld");
+
+ var columns = string.Join(",", _mediaStreamSaveColumns);
+
+ string[] queries = {
+ "REPLACE INTO mediastreams("+columns+") SELECT "+columns+" FROM MediaInfoOld.mediastreams;"
+ };
+
+ try
+ {
+ _connection.RunQueries(queries, _logger);
+ File.Delete(file);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error migrating media info database", ex);
+ }
+ }
+
+ private void MigrateChapters(string file)
+ {
+ 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;"
+ };
+
+ try
+ {
+ _connection.RunQueries(queries, _logger);
+ File.Delete(file);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error migrating chapter database", ex);
+ }
}
/// <summary>
@@ -187,11 +264,63 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// </summary>
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
- private string[] _retriveItemColumns =
+ private readonly string[] _retriveItemColumns =
{
"type",
"data",
- "IsOffline"
+ "StartDate",
+ "EndDate",
+ "IsOffline",
+ "ChannelId",
+ "IsMovie",
+ "IsSports",
+ "IsKids",
+ "IsSeries",
+ "IsLive",
+ "IsNews",
+ "IsPremiere",
+ "EpisodeTitle",
+ "IsRepeat",
+ "CommunityRating",
+ "CustomRating",
+ "IndexNumber",
+ "IsLocked",
+ "PreferredMetadataLanguage",
+ "PreferredMetadataCountryCode",
+ "IsHD",
+ "ExternalEtag",
+ "DateLastRefreshed"
+ };
+
+ private readonly string[] _mediaStreamSaveColumns =
+ {
+ "ItemId",
+ "StreamIndex",
+ "StreamType",
+ "Codec",
+ "Language",
+ "ChannelLayout",
+ "Profile",
+ "AspectRatio",
+ "Path",
+ "IsInterlaced",
+ "BitRate",
+ "Channels",
+ "SampleRate",
+ "IsDefault",
+ "IsForced",
+ "IsExternal",
+ "Height",
+ "Width",
+ "AverageFrameRate",
+ "RealFrameRate",
+ "Level",
+ "PixelFormat",
+ "BitDepth",
+ "IsAnamorphic",
+ "RefFrames",
+ "IsCabac",
+ "KeyFrames"
};
/// <summary>
@@ -211,6 +340,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
"IsKids",
"IsMovie",
"IsSports",
+ "IsSeries",
+ "IsLive",
+ "IsNews",
+ "IsPremiere",
+ "EpisodeTitle",
+ "IsRepeat",
"CommunityRating",
"CustomRating",
"IndexNumber",
@@ -235,7 +370,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
"DateCreated",
"DateModified",
"ForcedSortName",
- "IsOffline"
+ "IsOffline",
+ "LocationType",
+ "PreferredMetadataLanguage",
+ "PreferredMetadataCountryCode",
+ "IsHD",
+ "ExternalEtag",
+ "DateLastRefreshed"
};
_saveItemCommand = _connection.CreateCommand();
_saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -265,6 +406,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveChildrenCommand.Parameters.Add(_saveChildrenCommand, "@ParentId");
_saveChildrenCommand.Parameters.Add(_saveChildrenCommand, "@ItemId");
+ // People
_deletePeopleCommand = _connection.CreateCommand();
_deletePeopleCommand.CommandText = "delete from People where ItemId=@Id";
_deletePeopleCommand.Parameters.Add(_deletePeopleCommand, "@Id");
@@ -277,6 +419,36 @@ namespace MediaBrowser.Server.Implementations.Persistence
_savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType");
_savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder");
_savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder");
+
+ // Chapters
+ _deleteChaptersCommand = _connection.CreateCommand();
+ _deleteChaptersCommand.CommandText = "delete from " + ChaptersTableName + " where ItemId=@ItemId";
+ _deleteChaptersCommand.Parameters.Add(_deleteChaptersCommand, "@ItemId");
+
+ _saveChapterCommand = _connection.CreateCommand();
+ _saveChapterCommand.CommandText = "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)";
+
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ItemId");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ChapterIndex");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@StartPositionTicks");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@Name");
+ _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ImagePath");
+
+ // MediaStreams
+ _deleteStreamsCommand = _connection.CreateCommand();
+ _deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId";
+ _deleteStreamsCommand.Parameters.Add(_deleteStreamsCommand, "@ItemId");
+
+ _saveStreamCommand = _connection.CreateCommand();
+
+ _saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})",
+ string.Join(",", _mediaStreamSaveColumns),
+ string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray()));
+
+ foreach (var col in _mediaStreamSaveColumns)
+ {
+ _saveStreamCommand.Parameters.Add(_saveStreamCommand, "@" + col);
+ }
}
/// <summary>
@@ -357,12 +529,24 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsKids;
_saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsMovie;
_saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSports;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSeries;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsLive;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsNews;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsPremiere;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.EpisodeTitle;
+ _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsRepeat;
}
else
{
_saveItemCommand.GetParameter(index++).Value = null;
_saveItemCommand.GetParameter(index++).Value = null;
_saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
+ _saveItemCommand.GetParameter(index++).Value = null;
}
_saveItemCommand.GetParameter(index++).Value = item.CommunityRating;
@@ -405,6 +589,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(index++).Value = item.ForcedSortName;
_saveItemCommand.GetParameter(index++).Value = item.IsOffline;
+ _saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString();
+
+ _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataLanguage;
+ _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataCountryCode;
+ _saveItemCommand.GetParameter(index++).Value = item.IsHD;
+ _saveItemCommand.GetParameter(index++).Value = item.ExternalEtag;
+
+ if (item.DateLastRefreshed == default(DateTime))
+ {
+ _saveItemCommand.GetParameter(index++).Value = null;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed;
+ }
_saveItemCommand.Transaction = transaction;
@@ -511,7 +710,120 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (!reader.IsDBNull(2))
{
- item.IsOffline = reader.GetBoolean(2);
+ var hasStartDate = item as IHasStartDate;
+ if (hasStartDate != null)
+ {
+ hasStartDate.StartDate = reader.GetDateTime(2).ToUniversalTime();
+ }
+ }
+
+ if (!reader.IsDBNull(3))
+ {
+ item.EndDate = reader.GetDateTime(3).ToUniversalTime();
+ }
+
+ if (!reader.IsDBNull(4))
+ {
+ item.IsOffline = reader.GetBoolean(4);
+ }
+
+ if (!reader.IsDBNull(5))
+ {
+ item.ChannelId = reader.GetString(5);
+ }
+
+ var hasProgramAttributes = item as IHasProgramAttributes;
+ if (hasProgramAttributes != null)
+ {
+ if (!reader.IsDBNull(6))
+ {
+ hasProgramAttributes.IsMovie = reader.GetBoolean(6);
+ }
+
+ if (!reader.IsDBNull(7))
+ {
+ hasProgramAttributes.IsSports = reader.GetBoolean(7);
+ }
+
+ if (!reader.IsDBNull(8))
+ {
+ hasProgramAttributes.IsKids = reader.GetBoolean(8);
+ }
+
+ if (!reader.IsDBNull(9))
+ {
+ hasProgramAttributes.IsSeries = reader.GetBoolean(9);
+ }
+
+ if (!reader.IsDBNull(10))
+ {
+ hasProgramAttributes.IsLive = reader.GetBoolean(10);
+ }
+
+ if (!reader.IsDBNull(11))
+ {
+ hasProgramAttributes.IsNews = reader.GetBoolean(11);
+ }
+
+ if (!reader.IsDBNull(12))
+ {
+ hasProgramAttributes.IsPremiere = reader.GetBoolean(12);
+ }
+
+ if (!reader.IsDBNull(13))
+ {
+ hasProgramAttributes.EpisodeTitle = reader.GetString(13);
+ }
+
+ if (!reader.IsDBNull(14))
+ {
+ hasProgramAttributes.IsRepeat = reader.GetBoolean(14);
+ }
+ }
+
+ if (!reader.IsDBNull(15))
+ {
+ item.CommunityRating = reader.GetFloat(15);
+ }
+
+ if (!reader.IsDBNull(16))
+ {
+ item.CustomRating = reader.GetString(16);
+ }
+
+ if (!reader.IsDBNull(17))
+ {
+ item.IndexNumber = reader.GetInt32(17);
+ }
+
+ if (!reader.IsDBNull(18))
+ {
+ item.IsLocked = reader.GetBoolean(18);
+ }
+
+ if (!reader.IsDBNull(19))
+ {
+ item.PreferredMetadataLanguage = reader.GetString(19);
+ }
+
+ if (!reader.IsDBNull(20))
+ {
+ item.PreferredMetadataCountryCode = reader.GetString(20);
+ }
+
+ if (!reader.IsDBNull(21))
+ {
+ item.IsHD = reader.GetBoolean(21);
+ }
+
+ if (!reader.IsDBNull(22))
+ {
+ item.ExternalEtag = reader.GetString(22);
+ }
+
+ if (!reader.IsDBNull(23))
+ {
+ item.DateLastRefreshed = reader.GetDateTime(23).ToUniversalTime();
}
return item;
@@ -567,7 +879,25 @@ namespace MediaBrowser.Server.Implementations.Persistence
public IEnumerable<ChapterInfo> GetChapters(Guid id)
{
CheckDisposed();
- return _chapterRepository.GetChapters(id);
+ if (id == Guid.Empty)
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc";
+
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ yield return GetChapter(reader);
+ }
+ }
+ }
}
/// <summary>
@@ -580,7 +910,52 @@ namespace MediaBrowser.Server.Implementations.Persistence
public ChapterInfo GetChapter(Guid id, int index)
{
CheckDisposed();
- return _chapterRepository.GetChapter(id, index);
+ if (id == Guid.Empty)
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex";
+
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id;
+ cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ {
+ if (reader.Read())
+ {
+ return GetChapter(reader);
+ }
+ }
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets the chapter.
+ /// </summary>
+ /// <param name="reader">The reader.</param>
+ /// <returns>ChapterInfo.</returns>
+ private ChapterInfo GetChapter(IDataReader reader)
+ {
+ var chapter = new ChapterInfo
+ {
+ StartPositionTicks = reader.GetInt64(0)
+ };
+
+ if (!reader.IsDBNull(1))
+ {
+ chapter.Name = reader.GetString(1);
+ }
+
+ if (!reader.IsDBNull(2))
+ {
+ chapter.ImagePath = reader.GetString(2);
+ }
+
+ return chapter;
}
/// <summary>
@@ -597,10 +972,87 @@ namespace MediaBrowser.Server.Implementations.Persistence
/// or
/// cancellationToken
/// </exception>
- public Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public async Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken)
{
CheckDisposed();
- return _chapterRepository.SaveChapters(id, chapters, cancellationToken);
+
+ if (id == Guid.Empty)
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ if (chapters == null)
+ {
+ throw new ArgumentNullException("chapters");
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = _connection.BeginTransaction();
+
+ // First delete chapters
+ _deleteChaptersCommand.GetParameter(0).Value = id;
+
+ _deleteChaptersCommand.Transaction = transaction;
+
+ _deleteChaptersCommand.ExecuteNonQuery();
+
+ var index = 0;
+
+ foreach (var chapter in chapters)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ _saveChapterCommand.GetParameter(0).Value = id;
+ _saveChapterCommand.GetParameter(1).Value = index;
+ _saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks;
+ _saveChapterCommand.GetParameter(3).Value = chapter.Name;
+ _saveChapterCommand.GetParameter(4).Value = chapter.ImagePath;
+
+ _saveChapterCommand.Transaction = transaction;
+
+ _saveChapterCommand.ExecuteNonQuery();
+
+ index++;
+ }
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Failed to save chapters:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+
+ _writeLock.Release();
+ }
}
/// <summary>
@@ -649,18 +1101,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.Dispose();
_connection = null;
}
-
- if (_chapterRepository != null)
- {
- _chapterRepository.Dispose();
- _chapterRepository = null;
- }
-
- if (_mediaStreamsRepository != null)
- {
- _mediaStreamsRepository.Dispose();
- _mediaStreamsRepository = null;
- }
}
}
catch (Exception ex)
@@ -882,6 +1322,75 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ public QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ CheckDisposed();
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select guid,path from TypedBaseItems";
+
+ var whereClauses = GetWhereClauses(query, cmd, false);
+
+ 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;
+
+ cmd.CommandText += GetOrderByText(query);
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+
+ var list = new List<Tuple<Guid, string>>();
+ var count = 0;
+
+ _logger.Debug(cmd.CommandText);
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ var id = reader.GetGuid(0);
+ string path = null;
+
+ if (!reader.IsDBNull(1))
+ {
+ path = reader.GetString(1);
+ }
+ list.Add(new Tuple<Guid, string>(id, path));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+
+ return new QueryResult<Tuple<Guid, string>>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
+ }
+
public QueryResult<Guid> GetItemIds(InternalItemsQuery query)
{
if (query == null)
@@ -960,6 +1469,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
cmd.Parameters.Add(cmd, "@SchemaVersion", DbType.Int32).Value = LatestSchemaVersion;
}
+ if (query.IsOffline.HasValue)
+ {
+ whereClauses.Add("IsOffline=@IsOffline");
+ cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline;
+ }
+ if (query.LocationType.HasValue)
+ {
+ whereClauses.Add("LocationType=@LocationType");
+ cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationType.Value;
+ }
if (query.IsMovie.HasValue)
{
whereClauses.Add("IsMovie=@IsMovie");
@@ -1011,6 +1530,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add(string.Format("ChannelId in ({0})", inClause));
}
+ if (query.ParentId.HasValue)
+ {
+ whereClauses.Add("ParentId=@ParentId");
+ cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = query.ParentId.Value;
+ }
+
if (query.MinEndDate.HasValue)
{
whereClauses.Add("EndDate>=@MinEndDate");
@@ -1130,8 +1655,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
typeof(LiveTvVideoRecording),
typeof(LiveTvAudioRecording),
typeof(Series),
- typeof(LiveTvAudioRecording),
- typeof(LiveTvVideoRecording),
typeof(Audio),
typeof(MusicAlbum),
typeof(MusicArtist),
@@ -1156,7 +1679,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
typeof(UserRootFolder),
typeof(UserView),
typeof(Video),
- typeof(Year)
+ typeof(Year),
+ typeof(Channel)
};
private static Dictionary<string, string[]> GetTypeMapDictionary()
@@ -1216,11 +1740,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deletePeopleCommand.Transaction = transaction;
_deletePeopleCommand.ExecuteNonQuery();
+ // Delete chapters
+ _deleteChaptersCommand.GetParameter(0).Value = id;
+ _deleteChaptersCommand.Transaction = transaction;
+ _deleteChaptersCommand.ExecuteNonQuery();
+
+ // Delete media streams
+ _deleteStreamsCommand.GetParameter(0).Value = id;
+ _deleteStreamsCommand.Transaction = transaction;
+ _deleteStreamsCommand.ExecuteNonQuery();
+
// Delete the item
_deleteItemCommand.GetParameter(0).Value = id;
_deleteItemCommand.Transaction = transaction;
_deleteItemCommand.ExecuteNonQuery();
-
+
transaction.Commit();
}
catch (OperationCanceledException)
@@ -1327,18 +1861,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
- {
- CheckDisposed();
- return _mediaStreamsRepository.GetMediaStreams(query);
- }
-
- public Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
- {
- CheckDisposed();
- return _mediaStreamsRepository.SaveMediaStreams(id, streams, cancellationToken);
- }
-
public List<string> GetPeopleNames(InternalPeopleQuery query)
{
if (query == null)
@@ -1567,5 +2089,289 @@ namespace MediaBrowser.Server.Implementations.Persistence
return item;
}
+
+ public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
+ {
+ CheckDisposed();
+
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where";
+
+ cmdText += " ItemId=@ItemId";
+ cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId;
+
+ if (query.Type.HasValue)
+ {
+ cmdText += " AND StreamType=@StreamType";
+ cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString();
+ }
+
+ if (query.Index.HasValue)
+ {
+ cmdText += " AND StreamIndex=@StreamIndex";
+ cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value;
+ }
+
+ cmdText += " order by StreamIndex ASC";
+
+ cmd.CommandText = cmdText;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ {
+ while (reader.Read())
+ {
+ yield return GetMediaStream(reader);
+ }
+ }
+ }
+ }
+
+ public async Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
+ {
+ CheckDisposed();
+
+ if (id == Guid.Empty)
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ if (streams == null)
+ {
+ throw new ArgumentNullException("streams");
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ IDbTransaction transaction = null;
+
+ try
+ {
+ transaction = _connection.BeginTransaction();
+
+ // First delete chapters
+ _deleteStreamsCommand.GetParameter(0).Value = id;
+
+ _deleteStreamsCommand.Transaction = transaction;
+
+ _deleteStreamsCommand.ExecuteNonQuery();
+
+ foreach (var stream in streams)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var index = 0;
+
+ _saveStreamCommand.GetParameter(index++).Value = id;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Index;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString();
+ _saveStreamCommand.GetParameter(index++).Value = stream.Codec;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Language;
+ _saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Profile;
+ _saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Path;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.BitRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Channels;
+ _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsForced;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal;
+
+ _saveStreamCommand.GetParameter(index++).Value = stream.Width;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Height;
+ _saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate;
+ _saveStreamCommand.GetParameter(index++).Value = stream.Level;
+ _saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat;
+ _saveStreamCommand.GetParameter(index++).Value = stream.BitDepth;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic;
+ _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames;
+ _saveStreamCommand.GetParameter(index++).Value = stream.IsCabac;
+
+ if (stream.KeyFrames == null || stream.KeyFrames.Count == 0)
+ {
+ _saveStreamCommand.GetParameter(index++).Value = null;
+ }
+ else
+ {
+ _saveStreamCommand.GetParameter(index++).Value = string.Join(",", stream.KeyFrames.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray());
+ }
+
+ _saveStreamCommand.Transaction = transaction;
+ _saveStreamCommand.ExecuteNonQuery();
+ }
+
+ transaction.Commit();
+ }
+ catch (OperationCanceledException)
+ {
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Failed to save media streams:", e);
+
+ if (transaction != null)
+ {
+ transaction.Rollback();
+ }
+
+ throw;
+ }
+ finally
+ {
+ if (transaction != null)
+ {
+ transaction.Dispose();
+ }
+
+ _writeLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Gets the chapter.
+ /// </summary>
+ /// <param name="reader">The reader.</param>
+ /// <returns>ChapterInfo.</returns>
+ private MediaStream GetMediaStream(IDataReader reader)
+ {
+ var item = new MediaStream
+ {
+ Index = reader.GetInt32(1)
+ };
+
+ item.Type = (MediaStreamType)Enum.Parse(typeof(MediaStreamType), reader.GetString(2), true);
+
+ if (!reader.IsDBNull(3))
+ {
+ item.Codec = reader.GetString(3);
+ }
+
+ if (!reader.IsDBNull(4))
+ {
+ item.Language = reader.GetString(4);
+ }
+
+ if (!reader.IsDBNull(5))
+ {
+ item.ChannelLayout = reader.GetString(5);
+ }
+
+ if (!reader.IsDBNull(6))
+ {
+ item.Profile = reader.GetString(6);
+ }
+
+ if (!reader.IsDBNull(7))
+ {
+ item.AspectRatio = reader.GetString(7);
+ }
+
+ if (!reader.IsDBNull(8))
+ {
+ item.Path = reader.GetString(8);
+ }
+
+ item.IsInterlaced = reader.GetBoolean(9);
+
+ if (!reader.IsDBNull(10))
+ {
+ item.BitRate = reader.GetInt32(10);
+ }
+
+ if (!reader.IsDBNull(11))
+ {
+ item.Channels = reader.GetInt32(11);
+ }
+
+ if (!reader.IsDBNull(12))
+ {
+ item.SampleRate = reader.GetInt32(12);
+ }
+
+ item.IsDefault = reader.GetBoolean(13);
+ item.IsForced = reader.GetBoolean(14);
+ item.IsExternal = reader.GetBoolean(15);
+
+ if (!reader.IsDBNull(16))
+ {
+ item.Width = reader.GetInt32(16);
+ }
+
+ if (!reader.IsDBNull(17))
+ {
+ item.Height = reader.GetInt32(17);
+ }
+
+ if (!reader.IsDBNull(18))
+ {
+ item.AverageFrameRate = reader.GetFloat(18);
+ }
+
+ if (!reader.IsDBNull(19))
+ {
+ item.RealFrameRate = reader.GetFloat(19);
+ }
+
+ if (!reader.IsDBNull(20))
+ {
+ item.Level = reader.GetFloat(20);
+ }
+
+ if (!reader.IsDBNull(21))
+ {
+ item.PixelFormat = reader.GetString(21);
+ }
+
+ if (!reader.IsDBNull(22))
+ {
+ item.BitDepth = reader.GetInt32(22);
+ }
+
+ if (!reader.IsDBNull(23))
+ {
+ item.IsAnamorphic = reader.GetBoolean(23);
+ }
+
+ if (!reader.IsDBNull(24))
+ {
+ item.RefFrames = reader.GetInt32(24);
+ }
+
+ if (!reader.IsDBNull(25))
+ {
+ item.IsCabac = reader.GetBoolean(25);
+ }
+
+ if (!reader.IsDBNull(26))
+ {
+ var frames = reader.GetString(26);
+ if (!string.IsNullOrWhiteSpace(frames))
+ {
+ item.KeyFrames = frames.Split(',').Select(i => int.Parse(i, CultureInfo.InvariantCulture)).ToList();
+ }
+ }
+
+ return item;
+ }
+
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
deleted file mode 100644
index 9e97858d0..000000000
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
+++ /dev/null
@@ -1,633 +0,0 @@
-using System.Globalization;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Persistence
-{
- class SqliteMediaStreamsRepository
- {
- private IDbConnection _connection;
-
- private readonly ILogger _logger;
-
- private IDbCommand _deleteStreamsCommand;
- private IDbCommand _saveStreamCommand;
-
- public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
- {
- _connection = connection;
-
- _logger = logManager.GetLogger(GetType().Name);
- }
-
- /// <summary>
- /// Opens the connection to the database
- /// </summary>
- /// <returns>Task.</returns>
- public void Initialize()
- {
- var createTableCommand
- = "create table if not exists mediastreams ";
-
- // Add PixelFormat column
-
- createTableCommand += "(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, IsCabac BIT NULL, KeyFrames TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
-
- string[] queries = {
-
- createTableCommand,
-
- "create index if not exists idx_mediastreams on mediastreams(ItemId, StreamIndex)",
-
- //pragmas
- "pragma temp_store = memory",
-
- "pragma shrink_memory"
- };
-
- _connection.RunQueries(queries, _logger);
-
- AddPixelFormatColumnCommand();
- AddBitDepthCommand();
- AddIsAnamorphicColumn();
- AddIsCabacColumn();
- AddKeyFramesColumn();
- AddRefFramesCommand();
-
- PrepareStatements();
- }
-
- private void AddPixelFormatColumnCommand()
- {
- 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, "PixelFormat", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column PixelFormat TEXT");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private void AddBitDepthCommand()
- {
- 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, "BitDepth", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column BitDepth INT NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private void AddRefFramesCommand()
- {
- 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, "RefFrames", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column RefFrames INT NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private void AddIsCabacColumn()
- {
- 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, "IsCabac", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column IsCabac BIT NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private void AddKeyFramesColumn()
- {
- 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, "KeyFrames", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column KeyFrames TEXT NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private void AddIsAnamorphicColumn()
- {
- 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, "IsAnamorphic", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- }
- }
- }
- }
-
- var builder = new StringBuilder();
-
- builder.AppendLine("alter table mediastreams");
- builder.AppendLine("add column IsAnamorphic BIT NULL");
-
- _connection.RunQueries(new[] { builder.ToString() }, _logger);
- }
-
- private readonly string[] _saveColumns =
- {
- "ItemId",
- "StreamIndex",
- "StreamType",
- "Codec",
- "Language",
- "ChannelLayout",
- "Profile",
- "AspectRatio",
- "Path",
- "IsInterlaced",
- "BitRate",
- "Channels",
- "SampleRate",
- "IsDefault",
- "IsForced",
- "IsExternal",
- "Height",
- "Width",
- "AverageFrameRate",
- "RealFrameRate",
- "Level",
- "PixelFormat",
- "BitDepth",
- "IsAnamorphic",
- "RefFrames",
- "IsCabac",
- "KeyFrames"
- };
-
- /// <summary>
- /// The _write lock
- /// </summary>
- private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
- /// <summary>
- /// Prepares the statements.
- /// </summary>
- private void PrepareStatements()
- {
- _deleteStreamsCommand = _connection.CreateCommand();
- _deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId";
- _deleteStreamsCommand.Parameters.Add(_deleteStreamsCommand, "@ItemId");
-
- _saveStreamCommand = _connection.CreateCommand();
-
- _saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})",
- string.Join(",", _saveColumns),
- string.Join(",", _saveColumns.Select(i => "@" + i).ToArray()));
-
- foreach (var col in _saveColumns)
- {
- _saveStreamCommand.Parameters.Add(_saveStreamCommand, "@" + col);
- }
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
- {
- if (query == null)
- {
- throw new ArgumentNullException("query");
- }
-
- using (var cmd = _connection.CreateCommand())
- {
- var cmdText = "select " + string.Join(",", _saveColumns) + " from mediastreams where";
-
- cmdText += " ItemId=@ItemId";
- cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId;
-
- if (query.Type.HasValue)
- {
- cmdText += " AND StreamType=@StreamType";
- cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString();
- }
-
- if (query.Index.HasValue)
- {
- cmdText += " AND StreamIndex=@StreamIndex";
- cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value;
- }
-
- cmdText += " order by StreamIndex ASC";
-
- cmd.CommandText = cmdText;
-
- using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (reader.Read())
- {
- yield return GetMediaStream(reader);
- }
- }
- }
- }
-
- /// <summary>
- /// Gets the chapter.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>ChapterInfo.</returns>
- private MediaStream GetMediaStream(IDataReader reader)
- {
- var item = new MediaStream
- {
- Index = reader.GetInt32(1)
- };
-
- item.Type = (MediaStreamType)Enum.Parse(typeof(MediaStreamType), reader.GetString(2), true);
-
- if (!reader.IsDBNull(3))
- {
- item.Codec = reader.GetString(3);
- }
-
- if (!reader.IsDBNull(4))
- {
- item.Language = reader.GetString(4);
- }
-
- if (!reader.IsDBNull(5))
- {
- item.ChannelLayout = reader.GetString(5);
- }
-
- if (!reader.IsDBNull(6))
- {
- item.Profile = reader.GetString(6);
- }
-
- if (!reader.IsDBNull(7))
- {
- item.AspectRatio = reader.GetString(7);
- }
-
- if (!reader.IsDBNull(8))
- {
- item.Path = reader.GetString(8);
- }
-
- item.IsInterlaced = reader.GetBoolean(9);
-
- if (!reader.IsDBNull(10))
- {
- item.BitRate = reader.GetInt32(10);
- }
-
- if (!reader.IsDBNull(11))
- {
- item.Channels = reader.GetInt32(11);
- }
-
- if (!reader.IsDBNull(12))
- {
- item.SampleRate = reader.GetInt32(12);
- }
-
- item.IsDefault = reader.GetBoolean(13);
- item.IsForced = reader.GetBoolean(14);
- item.IsExternal = reader.GetBoolean(15);
-
- if (!reader.IsDBNull(16))
- {
- item.Width = reader.GetInt32(16);
- }
-
- if (!reader.IsDBNull(17))
- {
- item.Height = reader.GetInt32(17);
- }
-
- if (!reader.IsDBNull(18))
- {
- item.AverageFrameRate = reader.GetFloat(18);
- }
-
- if (!reader.IsDBNull(19))
- {
- item.RealFrameRate = reader.GetFloat(19);
- }
-
- if (!reader.IsDBNull(20))
- {
- item.Level = reader.GetFloat(20);
- }
-
- if (!reader.IsDBNull(21))
- {
- item.PixelFormat = reader.GetString(21);
- }
-
- if (!reader.IsDBNull(22))
- {
- item.BitDepth = reader.GetInt32(22);
- }
-
- if (!reader.IsDBNull(23))
- {
- item.IsAnamorphic = reader.GetBoolean(23);
- }
-
- if (!reader.IsDBNull(24))
- {
- item.RefFrames = reader.GetInt32(24);
- }
-
- if (!reader.IsDBNull(25))
- {
- item.IsCabac = reader.GetBoolean(25);
- }
-
- if (!reader.IsDBNull(26))
- {
- var frames = reader.GetString(26);
- if (!string.IsNullOrWhiteSpace(frames))
- {
- item.KeyFrames = frames.Split(',').Select(i => int.Parse(i, CultureInfo.InvariantCulture)).ToList();
- }
- }
-
- return item;
- }
-
- public async Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- if (streams == null)
- {
- throw new ArgumentNullException("streams");
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- IDbTransaction transaction = null;
-
- try
- {
- transaction = _connection.BeginTransaction();
-
- // First delete chapters
- _deleteStreamsCommand.GetParameter(0).Value = id;
-
- _deleteStreamsCommand.Transaction = transaction;
-
- _deleteStreamsCommand.ExecuteNonQuery();
-
- foreach (var stream in streams)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var index = 0;
-
- _saveStreamCommand.GetParameter(index++).Value = id;
- _saveStreamCommand.GetParameter(index++).Value = stream.Index;
- _saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString();
- _saveStreamCommand.GetParameter(index++).Value = stream.Codec;
- _saveStreamCommand.GetParameter(index++).Value = stream.Language;
- _saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout;
- _saveStreamCommand.GetParameter(index++).Value = stream.Profile;
- _saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio;
- _saveStreamCommand.GetParameter(index++).Value = stream.Path;
-
- _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced;
-
- _saveStreamCommand.GetParameter(index++).Value = stream.BitRate;
- _saveStreamCommand.GetParameter(index++).Value = stream.Channels;
- _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate;
-
- _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault;
- _saveStreamCommand.GetParameter(index++).Value = stream.IsForced;
- _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal;
-
- _saveStreamCommand.GetParameter(index++).Value = stream.Width;
- _saveStreamCommand.GetParameter(index++).Value = stream.Height;
- _saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate;
- _saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate;
- _saveStreamCommand.GetParameter(index++).Value = stream.Level;
- _saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat;
- _saveStreamCommand.GetParameter(index++).Value = stream.BitDepth;
- _saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic;
- _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames;
- _saveStreamCommand.GetParameter(index++).Value = stream.IsCabac;
-
- if (stream.KeyFrames == null || stream.KeyFrames.Count == 0)
- {
- _saveStreamCommand.GetParameter(index++).Value = null;
- }
- else
- {
- _saveStreamCommand.GetParameter(index++).Value = string.Join(",", stream.KeyFrames.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray());
- }
-
- _saveStreamCommand.Transaction = transaction;
- _saveStreamCommand.ExecuteNonQuery();
- }
-
- transaction.Commit();
- }
- catch (OperationCanceledException)
- {
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- catch (Exception e)
- {
- _logger.ErrorException("Failed to save media streams:", e);
-
- if (transaction != null)
- {
- transaction.Rollback();
- }
-
- throw;
- }
- finally
- {
- if (transaction != null)
- {
- transaction.Dispose();
- }
-
- _writeLock.Release();
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private readonly object _disposeLock = new object();
-
- /// <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)
- {
- try
- {
- lock (_disposeLock)
- {
- if (_connection != null)
- {
- if (_connection.IsOpen())
- {
- _connection.Close();
- }
-
- _connection.Dispose();
- _connection = null;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error disposing database", ex);
- }
- }
- }
- }
-}
-
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
index bce33e834..e7853b458 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
string[] queries = {
- "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, ItemName TEXT, ItemType TEXT, SeriesName TEXT, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastStatus TEXT, LastErrorMessage TEXT, MetadataProvidersRefreshed TEXT, ImageProvidersRefreshed TEXT, ItemDateModified DateTimeNull)",
+ "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, ItemName TEXT, ItemType TEXT, SeriesName TEXT, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastErrorMessage TEXT, ItemDateModified DateTimeNull)",
"create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)",
//pragmas
@@ -71,10 +71,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
"SeriesName",
"DateLastMetadataRefresh",
"DateLastImagesRefresh",
- "LastStatus",
"LastErrorMessage",
- "MetadataProvidersRefreshed",
- "ImageProvidersRefreshed",
"ItemDateModified"
};
@@ -188,19 +185,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (!reader.IsDBNull(6))
{
- result.LastStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(6), true);
+ result.LastErrorMessage = reader.GetString(6);
}
if (!reader.IsDBNull(7))
{
- result.LastErrorMessage = reader.GetString(7);
- }
-
- // Skip metadata and image providers
-
- if (!reader.IsDBNull(10))
- {
- result.ItemDateModified = reader.GetDateTime(10).ToUniversalTime();
+ result.ItemDateModified = reader.GetDateTime(7).ToUniversalTime();
}
return result;
@@ -229,11 +219,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveStatusCommand.GetParameter(3).Value = status.SeriesName;
_saveStatusCommand.GetParameter(4).Value = status.DateLastMetadataRefresh;
_saveStatusCommand.GetParameter(5).Value = status.DateLastImagesRefresh;
- _saveStatusCommand.GetParameter(6).Value = status.LastStatus.ToString();
- _saveStatusCommand.GetParameter(7).Value = status.LastErrorMessage;
- _saveStatusCommand.GetParameter(8).Value = string.Empty;
- _saveStatusCommand.GetParameter(9).Value = string.Empty;
- _saveStatusCommand.GetParameter(10).Value = status.ItemDateModified;
+ _saveStatusCommand.GetParameter(6).Value = status.LastErrorMessage;
+ _saveStatusCommand.GetParameter(7).Value = status.ItemDateModified;
_saveStatusCommand.Transaction = transaction;
diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
index 4b7e1c3a7..2402d3ec1 100644
--- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
@@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Photos
{
@@ -32,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Photos
ImageProcessor = imageProcessor;
}
- public virtual bool Supports(IHasImages item)
+ protected virtual bool Supports(IHasImages item)
{
return true;
}
@@ -91,11 +92,11 @@ namespace MediaBrowser.Server.Implementations.Photos
string cacheKey,
CancellationToken cancellationToken)
{
- var outputPath = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid() + ".png");
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
- var imageCreated = await CreateImage(item, itemsWithImages, outputPath, imageType, 0).ConfigureAwait(false);
+ var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N"));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension));
+ string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false);
- if (!imageCreated)
+ if (string.IsNullOrWhiteSpace(outputPath))
{
return ItemUpdateType.None;
}
@@ -116,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Photos
return parts.GetMD5().ToString("N");
}
- protected Task<bool> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 640, 360);
}
@@ -124,28 +125,43 @@ namespace MediaBrowser.Server.Implementations.Photos
protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
{
return items
- .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
+ .Select(i =>
+ {
+ var image = i.GetImageInfo(ImageType.Primary, 0);
+
+ if (image != null && image.IsLocalFile)
+ {
+ return image.Path;
+ }
+ image = i.GetImageInfo(ImageType.Thumb, 0);
+
+ if (image != null && image.IsLocalFile)
+ {
+ return image.Path;
+ }
+ return null;
+ })
.Where(i => !string.IsNullOrWhiteSpace(i));
}
- protected Task<bool> CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected Task<string> CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 400, 600);
}
- protected Task<bool> CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected Task<string> CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 600, 600);
}
- protected Task<bool> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
return CreateCollage(primaryItem, items, outputPath, width, height);
}
- private Task<bool> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ private async Task<string> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
- Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
+ FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath));
var options = new ImageCollageOptions
{
@@ -157,11 +173,16 @@ namespace MediaBrowser.Server.Implementations.Photos
if (options.InputPaths.Length == 0)
{
- return Task.FromResult(false);
+ return null;
+ }
+
+ if (!ImageProcessor.SupportsImageCollageCreation)
+ {
+ return null;
}
- ImageProcessor.CreateImageCollage(options);
- return Task.FromResult(true);
+ await ImageProcessor.CreateImageCollage(options).ConfigureAwait(false);
+ return outputPath;
}
public string Name
@@ -169,17 +190,19 @@ namespace MediaBrowser.Server.Implementations.Photos
get { return "Dynamic Image Provider"; }
}
- protected virtual async Task<bool> CreateImage(IHasImages item,
+ protected virtual async Task<string> CreateImage(IHasImages item,
List<BaseItem> itemsWithImages,
- string outputPath,
+ string outputPathWithoutExtension,
ImageType imageType,
int imageIndex)
{
if (itemsWithImages.Count == 0)
{
- return false;
+ return null;
}
+ string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
+
if (imageType == ImageType.Thumb)
{
return await CreateThumbCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
@@ -191,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.Photos
{
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
}
- if (item is PhotoAlbum || item is Playlist)
+ if (item is Playlist)
{
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
}
@@ -247,6 +270,11 @@ namespace MediaBrowser.Server.Implementations.Photos
if (image != null)
{
+ if (!image.IsLocalFile)
+ {
+ return false;
+ }
+
if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
{
return false;
@@ -268,6 +296,11 @@ namespace MediaBrowser.Server.Implementations.Photos
if (image != null)
{
+ if (!image.IsLocalFile)
+ {
+ return false;
+ }
+
if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
{
return false;
@@ -294,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.Photos
var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
return items
- .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
+ .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5())
.Take(limit)
.OrderBy(i => i.Name)
.ToList();
diff --git a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
index b55c76b8f..8b73d03d8 100644
--- a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
@@ -1,11 +1,12 @@
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Photos
{
@@ -19,9 +20,26 @@ namespace MediaBrowser.Server.Implementations.Photos
protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
{
var photoAlbum = (PhotoAlbum)item;
- var items = GetFinalItems(photoAlbum.Children.ToList());
+ var items = GetFinalItems(photoAlbum.Children.ToList(), 1);
return Task.FromResult(items);
}
+
+ protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, Model.Entities.ImageType imageType, int imageIndex)
+ {
+ var photoFile = itemsWithImages.Where(i => Path.HasExtension(i.Path)).Select(i => i.Path).FirstOrDefault();
+
+ if (string.IsNullOrWhiteSpace(photoFile))
+ {
+ return null;
+ }
+
+ var ext = Path.GetExtension(photoFile);
+
+ var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext);
+ File.Copy(photoFile, outputPath);
+
+ return outputPath;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
index 3ec41b6dc..4d3e091b1 100644
--- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
@@ -4,6 +4,8 @@ using MediaBrowser.Controller.Playlists;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.Playlists
{
@@ -46,17 +48,19 @@ namespace MediaBrowser.Server.Implementations.Playlists
public class PlaylistsDynamicFolder : IVirtualFolderCreator
{
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public PlaylistsDynamicFolder(IApplicationPaths appPaths)
+ public PlaylistsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem)
{
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
public BasePluginFolder GetFolder()
{
var path = Path.Combine(_appPaths.DataPath, "playlists");
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
return new PlaylistsFolder
{
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
index dcd9d21ea..d9e9fac2a 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -12,6 +12,7 @@ using MoreLinq;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Playlists
{
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
index 857cf743f..d9b3ed755 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
@@ -13,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Playlists
{
@@ -110,7 +111,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
try
{
- Directory.CreateDirectory(path);
+ _fileSystem.CreateDirectory(path);
var playlist = new Playlist
{
@@ -128,7 +129,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
await parentFolder.AddChild(playlist, CancellationToken.None).ConfigureAwait(false);
- await playlist.RefreshMetadata(new MetadataRefreshOptions { ForceSave = true }, CancellationToken.None)
+ await playlist.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { ForceSave = true }, CancellationToken.None)
.ConfigureAwait(false);
if (options.ItemIdList.Count > 0)
@@ -150,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
private string GetTargetPath(string path)
{
- while (Directory.Exists(path))
+ while (_fileSystem.DirectoryExists(path))
{
path += "1";
}
@@ -196,7 +197,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions
+ _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true
});
@@ -223,12 +224,43 @@ namespace MediaBrowser.Server.Implementations.Playlists
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions
+ _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem)
{
ForceSave = true
});
}
+ public async Task MoveItem(string playlistId, string entryId, int newIndex)
+ {
+ var playlist = _libraryManager.GetItemById(playlistId) as Playlist;
+
+ if (playlist == null)
+ {
+ throw new ArgumentException("No Playlist exists with the supplied Id");
+ }
+
+ var children = playlist.GetManageableItems().ToList();
+
+ var oldIndex = children.FindIndex(i => string.Equals(entryId, i.Item1.Id, StringComparison.OrdinalIgnoreCase));
+
+ if (oldIndex == newIndex)
+ {
+ return;
+ }
+
+ if (newIndex > oldIndex)
+ {
+ newIndex--;
+ }
+
+ var item = playlist.LinkedChildren[oldIndex];
+
+ playlist.LinkedChildren.Remove(item);
+ playlist.LinkedChildren.Insert(newIndex, item);
+
+ await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ }
+
public Folder GetPlaylistsFolder(string userId)
{
return _libraryManager.RootFolder.Children.OfType<PlaylistsFolder>()
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index b23aaeeff..355603fae 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -11,6 +11,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
@@ -39,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
private readonly IApplicationPaths _appPaths;
private readonly IEncodingManager _encodingManager;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="ChapterImagesTask" /> class.
@@ -46,13 +49,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <param name="logManager">The log manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="itemRepo">The item repo.</param>
- public ChapterImagesTask(ILogManager logManager, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager)
+ public ChapterImagesTask(ILogManager logManager, ILibraryManager libraryManager, IItemRepository itemRepo, IApplicationPaths appPaths, IEncodingManager encodingManager, IFileSystem fileSystem)
{
_logger = logManager.GetLogger(GetType().Name);
_libraryManager = libraryManager;
_itemRepo = itemRepo;
_appPaths = appPaths;
_encodingManager = encodingManager;
+ _fileSystem = fileSystem;
}
/// <summary>
@@ -94,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
try
{
- previouslyFailedImages = File.ReadAllText(failHistoryPath)
+ previouslyFailedImages = _fileSystem.ReadAllText(failHistoryPath)
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.ToList();
}
@@ -132,9 +136,9 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var parentPath = Path.GetDirectoryName(failHistoryPath);
- Directory.CreateDirectory(parentPath);
+ _fileSystem.CreateDirectory(parentPath);
- File.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
+ _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
}
numComplete++;
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
index a65b46f64..90682d5b0 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.ScheduledTasks
{
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 70a4cb439..8d3273421 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -29,6 +29,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Net;
namespace MediaBrowser.Server.Implementations.Session
{
@@ -1276,7 +1277,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
if (!_deviceManager.CanAccessDevice(user.Id.ToString("N"), request.DeviceId))
{
- throw new UnauthorizedAccessException("User is not allowed access from this device.");
+ throw new SecurityException("User is not allowed access from this device.");
}
}
@@ -1286,7 +1287,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
EventHelper.FireEventIfNotNull(AuthenticationFailed, this, new GenericEventArgs<AuthenticationRequest>(request), _logger);
- throw new UnauthorizedAccessException("Invalid user or password entered.");
+ throw new SecurityException("Invalid user or password entered.");
}
var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName).ConfigureAwait(false);
@@ -1322,8 +1323,9 @@ namespace MediaBrowser.Server.Implementations.Session
if (existing.Items.Length > 0)
{
- _logger.Debug("Reissuing access token");
- return existing.Items[0].AccessToken;
+ var token = existing.Items[0].AccessToken;
+ _logger.Info("Reissuing access token: " + token);
+ return token;
}
var newToken = new AuthenticationInfo
@@ -1338,7 +1340,7 @@ namespace MediaBrowser.Server.Implementations.Session
AccessToken = Guid.NewGuid().ToString("N")
};
- _logger.Debug("Creating new access token for user {0}", userId);
+ _logger.Info("Creating new access token for user {0}", userId);
await _authRepo.Create(newToken, CancellationToken.None).ConfigureAwait(false);
return newToken.AccessToken;
@@ -1351,6 +1353,8 @@ namespace MediaBrowser.Server.Implementations.Session
throw new ArgumentNullException("accessToken");
}
+ _logger.Info("Logging out access token {0}", accessToken);
+
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
Limit = 1,
diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
index 86ef58e42..cff72ae58 100644
--- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
@@ -18,6 +18,7 @@ using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using Interfaces.IO;
namespace MediaBrowser.Server.Implementations.Sync
@@ -83,12 +84,7 @@ namespace MediaBrowser.Server.Implementations.Sync
foreach (var localItem in localItems)
{
- // TODO: Remove this after a while
- if (string.IsNullOrWhiteSpace(localItem.FileId))
- {
- jobItemIds.Add(localItem.SyncJobItemId);
- }
- else if (remoteIds.Contains(localItem.FileId, StringComparer.OrdinalIgnoreCase))
+ if (remoteIds.Contains(localItem.FileId, StringComparer.OrdinalIgnoreCase))
{
jobItemIds.Add(localItem.SyncJobItemId);
}
@@ -147,7 +143,14 @@ namespace MediaBrowser.Server.Implementations.Sync
progress.Report(totalProgress);
});
- await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
+ try
+ {
+ await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error syncing item", ex);
+ }
numComplete++;
startingPercent = numComplete;
@@ -322,12 +325,6 @@ namespace MediaBrowser.Server.Implementations.Sync
{
var files = localItem.AdditionalFiles.ToList();
- // TODO: Remove this. Have to check it for now since this is a new property
- if (!string.IsNullOrWhiteSpace(localItem.FileId))
- {
- files.Insert(0, localItem.FileId);
- }
-
foreach (var file in files)
{
_logger.Debug("Removing {0} from {1}.", file, target.Name);
diff --git a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
index 6f09e96f0..dca831f73 100644
--- a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Sync
{
diff --git a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
index 9477a23f1..52c9f9cee 100644
--- a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Sync
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
index 5347e1d83..2efed7992 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Sync
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 1061a373e..95934908d 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -23,6 +23,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Sync
{
@@ -178,9 +179,13 @@ namespace MediaBrowser.Server.Implementations.Sync
job.Progress = null;
}
- if (jobItems.All(i => i.Status == SyncJobItemStatus.Queued))
+ if (jobItems.Any(i => i.Status == SyncJobItemStatus.Transferring))
{
- job.Status = SyncJobStatus.Queued;
+ job.Status = SyncJobStatus.Transferring;
+ }
+ else if (jobItems.Any(i => i.Status == SyncJobItemStatus.Converting))
+ {
+ job.Status = SyncJobStatus.Converting;
}
else if (jobItems.All(i => i.Status == SyncJobItemStatus.Failed))
{
@@ -194,14 +199,6 @@ namespace MediaBrowser.Server.Implementations.Sync
{
job.Status = SyncJobStatus.ReadyToTransfer;
}
- else if (jobItems.All(i => i.Status == SyncJobItemStatus.Transferring))
- {
- job.Status = SyncJobStatus.Transferring;
- }
- else if (jobItems.Any(i => i.Status == SyncJobItemStatus.Converting))
- {
- job.Status = SyncJobStatus.Converting;
- }
else if (jobItems.All(i => i.Status == SyncJobItemStatus.Cancelled || i.Status == SyncJobItemStatus.Failed || i.Status == SyncJobItemStatus.Synced || i.Status == SyncJobItemStatus.RemovedFromDevice))
{
if (jobItems.Any(i => i.Status == SyncJobItemStatus.Failed))
@@ -702,7 +699,7 @@ namespace MediaBrowser.Server.Implementations.Sync
var path = Path.Combine(temporaryPath, filename);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, cancellationToken).ConfigureAwait(false))
{
@@ -868,7 +865,7 @@ namespace MediaBrowser.Server.Implementations.Sync
private async Task<MediaSourceInfo> GetEncodedMediaSource(string path, User user, bool isVideo)
{
- var item = _libraryManager.ResolvePath(new FileInfo(path));
+ var item = _libraryManager.ResolvePath(_fileSystem.GetFileSystemInfo(path));
await item.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index 18fcb4e79..c715c3f50 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -32,6 +32,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.Sync
{
@@ -516,60 +517,25 @@ namespace MediaBrowser.Server.Implementations.Sync
return false;
}
- if (!item.RunTimeTicks.HasValue)
- {
- return false;
- }
-
var video = item as Video;
if (video != null)
{
- if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.HdDvd)
- {
- return false;
- }
-
if (video.IsPlaceHolder)
{
return false;
}
- if (video.IsArchive)
- {
- return false;
- }
-
- if (video.IsStacked)
- {
- return false;
- }
-
if (video.IsShortcut)
{
return false;
}
}
- var game = item as Game;
- if (game != null)
- {
- if (game.IsMultiPart)
- {
- return false;
- }
- }
-
if (item is LiveTvChannel || item is IChannelItem)
{
return false;
}
- // It would be nice to support these later
- if (item is Game || item is Book)
- {
- return false;
- }
-
return true;
}
@@ -784,27 +750,27 @@ namespace MediaBrowser.Server.Implementations.Sync
if (jobItem.IsMarkedForRemoval)
{
// Tell the device to remove it since it has been marked for removal
- _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.ItemId);
+ _logger.Info("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.ItemId);
removeFromDevice = true;
}
else if (user == null)
{
// Tell the device to remove it since the user is gone now
- _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.ItemId);
+ _logger.Info("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.ItemId);
removeFromDevice = true;
}
else if (!IsLibraryItemAvailable(libraryItem))
{
// Tell the device to remove it since it's no longer available
- _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.ItemId);
+ _logger.Info("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.ItemId);
removeFromDevice = true;
}
else if (job.UnwatchedOnly)
{
- if (libraryItem.IsPlayed(user) && libraryItem is Video)
+ if (libraryItem is Video && libraryItem.IsPlayed(user))
{
// Tell the device to remove it since it has been played
- _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.ItemId);
+ _logger.Info("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.ItemId);
removeFromDevice = true;
}
}
@@ -818,8 +784,9 @@ namespace MediaBrowser.Server.Implementations.Sync
}
else
{
- _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.ItemId);
+ _logger.Info("Setting status to Queued for {0} because it is no longer on the device.", jobItem.ItemId);
jobItem.Status = SyncJobItemStatus.Queued;
+ jobItem.Progress = 0;
}
requiresSaving = true;
}
@@ -889,27 +856,27 @@ namespace MediaBrowser.Server.Implementations.Sync
if (jobItem.IsMarkedForRemoval)
{
// Tell the device to remove it since it has been marked for removal
- _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.Id);
+ _logger.Info("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.Id);
removeFromDevice = true;
}
else if (user == null)
{
// Tell the device to remove it since the user is gone now
- _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.Id);
+ _logger.Info("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.Id);
removeFromDevice = true;
}
else if (!IsLibraryItemAvailable(libraryItem))
{
// Tell the device to remove it since it's no longer available
- _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.Id);
+ _logger.Info("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.Id);
removeFromDevice = true;
}
else if (job.UnwatchedOnly)
{
- if (libraryItem.IsPlayed(user) && libraryItem is Video)
+ if (libraryItem is Video && libraryItem.IsPlayed(user))
{
// Tell the device to remove it since it has been played
- _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.Id);
+ _logger.Info("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.Id);
removeFromDevice = true;
}
}
@@ -923,8 +890,9 @@ namespace MediaBrowser.Server.Implementations.Sync
}
else
{
- _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.Id);
+ _logger.Info("Setting status to Queued for {0} because it is no longer on the device.", jobItem.Id);
jobItem.Status = SyncJobItemStatus.Queued;
+ jobItem.Progress = 0;
}
requiresSaving = true;
}
@@ -997,8 +965,6 @@ namespace MediaBrowser.Server.Implementations.Sync
return false;
}
- // TODO: Make sure it hasn't been deleted
-
return true;
}
diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
index 676adad34..41d56d959 100644
--- a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
@@ -11,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
using Interfaces.IO;
namespace MediaBrowser.Server.Implementations.Sync
diff --git a/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs b/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
deleted file mode 100644
index 2711c08aa..000000000
--- a/MediaBrowser.Server.Implementations/Themes/AppThemeManager.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Themes;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Themes;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Themes
-{
- public class AppThemeManager : IAppThemeManager
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
- private readonly IJsonSerializer _json;
- private readonly ILogger _logger;
-
- private readonly string[] _supportedImageExtensions = { ".png", ".jpg", ".jpeg" };
-
- public AppThemeManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer json, ILogger logger)
- {
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- _json = json;
- _logger = logger;
- }
-
- private string ThemePath
- {
- get
- {
- return Path.Combine(_appPaths.ProgramDataPath, "appthemes");
- }
- }
-
- private string GetThemesPath(string applicationName)
- {
- if (string.IsNullOrWhiteSpace(applicationName))
- {
- throw new ArgumentNullException("applicationName");
- }
-
- // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
- var name = _fileSystem.GetValidFilename(applicationName.ToLower());
-
- return Path.Combine(ThemePath, name);
- }
-
- private string GetThemePath(string applicationName, string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- // Force everything lowercase for consistency and maximum compatibility with case-sensitive file systems
- name = _fileSystem.GetValidFilename(name.ToLower());
-
- return Path.Combine(GetThemesPath(applicationName), name);
- }
-
- private string GetImagesPath(string applicationName, string themeName)
- {
- return Path.Combine(GetThemePath(applicationName, themeName), "images");
- }
-
- public IEnumerable<AppThemeInfo> GetThemes(string applicationName)
- {
- var path = GetThemesPath(applicationName);
-
- try
- {
- return Directory
- .EnumerateFiles(path, "*", SearchOption.AllDirectories)
- .Where(i => string.Equals(Path.GetExtension(i), ".json", StringComparison.OrdinalIgnoreCase))
- .Select(i =>
- {
- try
- {
- return _json.DeserializeFromFile<AppThemeInfo>(i);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deserializing {0}", ex, i);
- return null;
- }
-
- }).Where(i => i != null);
- }
- catch (DirectoryNotFoundException)
- {
- return new List<AppThemeInfo>();
- }
- }
-
- public AppTheme GetTheme(string applicationName, string name)
- {
- var themePath = GetThemePath(applicationName, name);
- var file = Path.Combine(themePath, "theme.json");
-
- var imagesPath = GetImagesPath(applicationName, name);
-
- var theme = _json.DeserializeFromFile<AppTheme>(file);
-
- theme.Images = new DirectoryInfo(imagesPath)
- .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
- .Where(i => _supportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
- .Select(GetThemeImage)
- .ToList();
-
- return theme;
- }
-
- private ThemeImage GetThemeImage(FileInfo file)
- {
- var dateModified = _fileSystem.GetLastWriteTimeUtc(file);
-
- var cacheTag = (file.FullName + dateModified.Ticks).GetMD5().ToString("N");
-
- return new ThemeImage
- {
- CacheTag = cacheTag,
- Name = file.Name
- };
- }
-
- public void SaveTheme(AppTheme theme)
- {
- var themePath = GetThemePath(theme.AppName, theme.Name);
- var file = Path.Combine(themePath, "theme.json");
-
- Directory.CreateDirectory(themePath);
-
- // Clone it so that we don't serialize all the images - they're always dynamic
- var clone = new AppTheme
- {
- AppName = theme.AppName,
- Name = theme.Name,
- Options = theme.Options,
- Images = null
- };
-
- _json.SerializeToFile(clone, file);
- }
-
- public InternalThemeImage GetImageImageInfo(string applicationName, string themeName, string imageName)
- {
- var imagesPath = GetImagesPath(applicationName, themeName);
-
- var file = new DirectoryInfo(imagesPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly)
- .First(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase));
-
- var themeImage = GetThemeImage(file);
-
- return new InternalThemeImage
- {
- CacheTag = themeImage.CacheTag,
- Name = themeImage.Name,
- Path = file.FullName,
- DateModified = _fileSystem.GetLastWriteTimeUtc(file)
- };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
index 7054515b6..de0b0e758 100644
--- a/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
@@ -10,8 +10,10 @@ using MediaBrowser.Server.Implementations.Photos;
using MoreLinq;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.UserViews
{
@@ -91,18 +93,20 @@ namespace MediaBrowser.Server.Implementations.UserViews
return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
}
- public override bool Supports(IHasImages item)
+ protected override bool Supports(IHasImages item)
{
return item is CollectionFolder;
}
- protected override async Task<bool> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex)
+ protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
+ var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
+
if (imageType == ImageType.Primary)
{
if (itemsWithImages.Count == 0)
{
- return false;
+ return null;
}
return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
index 8321ab952..cdffadcd7 100644
--- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -11,8 +11,10 @@ using MediaBrowser.Server.Implementations.Photos;
using MoreLinq;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Implementations.UserViews
{
@@ -66,14 +68,14 @@ namespace MediaBrowser.Server.Implementations.UserViews
}
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
- var recursive = isUsingCollectionStrip && !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
var result = await view.GetItems(new InternalItemsQuery
{
User = (view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null),
CollapseBoxSetItems = false,
Recursive = recursive,
- ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" }
+ ExcludeItemTypes = new[] { "UserView", "CollectionFolder" }
}).ConfigureAwait(false);
@@ -130,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList());
}
- public override bool Supports(IHasImages item)
+ protected override bool Supports(IHasImages item)
{
var view = item as UserView;
if (view != null)
@@ -147,20 +149,29 @@ namespace MediaBrowser.Server.Implementations.UserViews
{
CollectionType.Movies,
CollectionType.TvShows,
- CollectionType.Music
+ CollectionType.Music,
+ CollectionType.Games,
+ CollectionType.Books,
+ CollectionType.MusicVideos,
+ CollectionType.HomeVideos,
+ CollectionType.BoxSets,
+ CollectionType.Playlists,
+ CollectionType.Photos
};
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
}
- protected override async Task<bool> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPath, ImageType imageType, int imageIndex)
+ protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
+ var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
+
var view = (UserView)item;
if (imageType == ImageType.Primary && IsUsingCollectionStrip(view))
{
if (itemsWithImages.Count == 0)
{
- return false;
+ return null;
}
return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 92388c99e..22206997f 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
- <package id="MediaBrowser.Naming" version="1.0.0.37" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.38" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
- <package id="morelinq" version="1.1.0" targetFramework="net45" />
+ <package id="morelinq" version="1.1.1" targetFramework="net45" />
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
- <package id="SocketHttpListener" version="1.0.0.7" targetFramework="net45" />
+ <package id="SocketHttpListener" version="1.0.0.10" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Mac.userprefs b/MediaBrowser.Server.Mac.userprefs
index b5f227685..cd108e550 100644
--- a/MediaBrowser.Server.Mac.userprefs
+++ b/MediaBrowser.Server.Mac.userprefs
@@ -1,25 +1,6 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release" />
- <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Common/Properties/AssemblyInfo.cs">
- <Files>
- <File FileName="MediaBrowser.Server.Mac/ImageMagickSharp.dll.config" Line="1" Column="1" />
- <File FileName="MediaBrowser.Server.Startup.Common/ApplicationHost.cs" Line="1" Column="18" />
- <File FileName="MediaBrowser.Api/ConnectService.cs" Line="7" Column="22" />
- <File FileName="MediaBrowser.Server.Mac/AppController.cs" Line="22" Column="1" />
- <File FileName="MediaBrowser.Server.Mac/AppDelegate.cs" Line="24" Column="1" />
- <File FileName="MediaBrowser.Server.Mac/Main.cs" Line="60" Column="4" />
- <File FileName="SharedVersion.cs" Line="1" Column="1" />
- <File FileName="MediaBrowser.Common/Properties/AssemblyInfo.cs" Line="9" Column="12" />
- </Files>
- <Pads>
- <Pad Id="ProjectPad">
- <State expanded="True">
- <Node name="Emby.Server.Mac" selected="True" />
- <Node name="OpenSubtitlesHandler" expanded="True" />
- </State>
- </Pad>
- </Pads>
- </MonoDevelop.Ide.Workbench>
+ <MonoDevelop.Ide.Workbench />
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore>
<Breakpoint file="/Users/luke/MediaBrowser/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs" line="233" column="1" />
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index cd010e1c1..ecb89b78c 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -12,7 +12,6 @@
<StartupObject>MediaBrowser.Server.Mono.MainClass</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
@@ -53,6 +52,10 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="Mono.Posix, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
@@ -62,6 +65,10 @@
<HintPath>..\ThirdParty\Mono.Security\Mono.Security.dll</HintPath>
<Private>False</Private>
</Reference>
+ <Reference Include="Patterns.Logging, Version=1.0.5494.41209, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 3b2d14588..ba6d7ad1f 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
@@ -13,6 +13,12 @@ namespace MediaBrowser.Server.Mono.Native
{
public abstract class BaseMonoApp : INativeApp
{
+ protected StartupOptions StartupOptions { get; private set; }
+ protected BaseMonoApp(StartupOptions startupOptions)
+ {
+ StartupOptions = startupOptions;
+ }
+
/// <summary>
/// Shutdowns this instance.
/// </summary>
@@ -109,6 +115,14 @@ namespace MediaBrowser.Server.Mono.Native
}
}
+ public bool SupportsLibraryMonitor
+ {
+ get
+ {
+ return false;
+ }
+ }
+
public void ConfigureAutoRun(bool autorun)
{
}
@@ -165,6 +179,7 @@ namespace MediaBrowser.Server.Mono.Native
}
private Uname _unixName;
+
private Uname GetUnixName()
{
if (_unixName == null)
diff --git a/MediaBrowser.Server.Mono/Native/NativeApp.cs b/MediaBrowser.Server.Mono/Native/NativeApp.cs
index cd1e78e35..500555647 100644
--- a/MediaBrowser.Server.Mono/Native/NativeApp.cs
+++ b/MediaBrowser.Server.Mono/Native/NativeApp.cs
@@ -7,6 +7,11 @@ namespace MediaBrowser.Server.Mono.Native
/// </summary>
internal class NativeApp : BaseMonoApp
{
+ public NativeApp(StartupOptions startupOptions)
+ : base(startupOptions)
+ {
+ }
+
/// <summary>
/// Shutdowns this instance.
/// </summary>
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 7b201e555..908f3b136 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -14,6 +14,8 @@ using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Server.Implementations.Logging;
namespace MediaBrowser.Server.Mono
{
@@ -75,9 +77,10 @@ namespace MediaBrowser.Server.Mono
// Allow all https requests
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
- var fileSystem = new CommonFileSystem(logManager.GetLogger("FileSystem"), false, true);
+ var fileSystem = new ManagedFileSystem(new PatternsLogger(logManager.GetLogger("FileSystem")), false, true);
+ fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
- var nativeApp = new NativeApp();
+ var nativeApp = new NativeApp(options);
_appHost = new ApplicationHost(appPaths, logManager, options, fileSystem, "MBServer.Mono", nativeApp);
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index 120360cd4..6a2a6c1e5 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 9ecd0764a..aeafc1ede 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Implementations;
using MediaBrowser.Common.Implementations.ScheduledTasks;
-using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
@@ -42,7 +41,6 @@ using MediaBrowser.Controller.Social;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Sync;
-using MediaBrowser.Controller.Themes;
using MediaBrowser.Controller.TV;
using MediaBrowser.Dlna;
using MediaBrowser.Dlna.ConnectionManager;
@@ -87,7 +85,6 @@ using MediaBrowser.Server.Implementations.ServerManager;
using MediaBrowser.Server.Implementations.Session;
using MediaBrowser.Server.Implementations.Social;
using MediaBrowser.Server.Implementations.Sync;
-using MediaBrowser.Server.Implementations.Themes;
using MediaBrowser.Server.Implementations.TV;
using MediaBrowser.Server.Startup.Common.FFMpeg;
using MediaBrowser.Server.Startup.Common.Migrations;
@@ -101,6 +98,7 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Startup.Common
{
@@ -124,7 +122,7 @@ namespace MediaBrowser.Server.Startup.Common
/// <returns>IConfigurationManager.</returns>
protected override IConfigurationManager GetConfigurationManager()
{
- return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer);
+ return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager);
}
/// <summary>
@@ -262,6 +260,11 @@ namespace MediaBrowser.Server.Startup.Common
get { return NativeApp.SupportsRunningAsService; }
}
+ public bool SupportsLibraryMonitor
+ {
+ get { return NativeApp.SupportsLibraryMonitor; }
+ }
+
/// <summary>
/// Gets the name.
/// </summary>
@@ -314,6 +317,7 @@ namespace MediaBrowser.Server.Startup.Common
await base.RunStartupTasks().ConfigureAwait(false);
Logger.Info("Core startup complete");
+ HttpServer.GlobalResponse = null;
Parallel.ForEach(GetExports<IServerEntryPoint>(), entryPoint =>
{
@@ -328,29 +332,25 @@ namespace MediaBrowser.Server.Startup.Common
});
LogManager.RemoveConsoleOutput();
+
+ PerformPostInitMigrations();
}
- public override async Task Init(IProgress<double> progress)
+ public override Task Init(IProgress<double> progress)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
PerformPreInitMigrations();
- await base.Init(progress).ConfigureAwait(false);
-
- PerformPostInitMigrations();
+ return base.Init(progress);
}
private void PerformPreInitMigrations()
{
var migrations = new List<IVersionMigration>
{
- new MigrateUserFolders(ApplicationPaths, FileSystemManager),
- new RenameXbmcOptions(ServerConfigurationManager),
- new RenameXmlOptions(ServerConfigurationManager),
- new DeprecatePlugins(ApplicationPaths, FileSystemManager),
- new DeleteDlnaProfiles(ApplicationPaths, FileSystemManager)
+ new RenameXmlOptions(ServerConfigurationManager)
};
foreach (var task in migrations)
@@ -361,7 +361,10 @@ namespace MediaBrowser.Server.Startup.Common
private void PerformPostInitMigrations()
{
- var migrations = new List<IVersionMigration>();
+ var migrations = new List<IVersionMigration>
+ {
+ new Release5767(ServerConfigurationManager, TaskManager)
+ };
foreach (var task in migrations)
{
@@ -422,7 +425,7 @@ namespace MediaBrowser.Server.Startup.Common
var musicManager = new MusicManager(LibraryManager);
RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager));
- LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
+ LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, this);
RegisterSingleInstance(LibraryMonitor);
ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager);
@@ -434,6 +437,7 @@ namespace MediaBrowser.Server.Startup.Common
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, "Emby", "web/index.html");
+ HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
RegisterSingleInstance(HttpServer, false);
progress.Report(10);
@@ -458,7 +462,7 @@ namespace MediaBrowser.Server.Startup.Common
var encryptionManager = new EncryptionManager();
RegisterSingleInstance<IEncryptionManager>(encryptionManager);
- ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager);
+ ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager);
RegisterSingleInstance(ConnectManager);
DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
@@ -472,25 +476,22 @@ namespace MediaBrowser.Server.Startup.Common
progress.Report(15);
- ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
+ ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
RegisterSingleInstance(ChannelManager);
- MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer);
+ MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager);
RegisterSingleInstance(MediaSourceManager);
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
RegisterSingleInstance(SessionManager);
- var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
- RegisterSingleInstance<IAppThemeManager>(appThemeManager);
-
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this);
RegisterSingleInstance<IDlnaManager>(dlnaManager);
var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient);
RegisterSingleInstance<IConnectionManager>(connectionManager);
- CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"));
+ CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager);
RegisterSingleInstance(CollectionManager);
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager);
@@ -499,7 +500,7 @@ namespace MediaBrowser.Server.Startup.Common
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager);
RegisterSingleInstance(LiveTvManager);
- UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, PlaylistManager, CollectionManager, ServerConfigurationManager);
+ 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);
@@ -522,8 +523,7 @@ namespace MediaBrowser.Server.Startup.Common
await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
progress.Report(90);
- EncodingManager = new EncodingManager(FileSystemManager, Logger,
- MediaEncoder, ChapterManager);
+ EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager);
RegisterSingleInstance(EncodingManager);
var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
@@ -564,7 +564,7 @@ namespace MediaBrowser.Server.Startup.Common
int.TryParse(_startupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses);
}
- return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder(), maxConcurrentImageProcesses);
+ return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder(), maxConcurrentImageProcesses, () => LibraryManager);
}
private IImageEncoder GetImageEncoder()
@@ -573,15 +573,24 @@ namespace MediaBrowser.Server.Startup.Common
{
try
{
- return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient);
+ return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager);
}
catch (Exception ex)
{
- Logger.ErrorException("Error loading ImageMagick. Will revert to GDI.", ex);
+ Logger.Error("Error loading ImageMagick. Will revert to GDI.");
}
}
- return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI"));
+ try
+ {
+ return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI"));
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("Error loading GDI. Will revert to NullImageEncoder.");
+ }
+
+ return new NullImageEncoder();
}
protected override INetworkManager CreateNetworkManager(ILogger logger)
@@ -598,9 +607,7 @@ namespace MediaBrowser.Server.Startup.Common
var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment)
.GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false);
- new FFmpegValidator(Logger, ApplicationPaths).Validate(info);
-
- MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
+ var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
JsonSerializer,
info.EncoderPath,
info.ProbePath,
@@ -614,7 +621,17 @@ namespace MediaBrowser.Server.Startup.Common
SessionManager,
() => SubtitleEncoder,
() => MediaSourceManager);
+
+ MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder);
+
+ Task.Run(() =>
+ {
+ var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(info);
+
+ mediaEncoder.SetAvailableDecoders(result.Item1);
+ mediaEncoder.SetAvailableEncoders(result.Item2);
+ });
}
/// <summary>
@@ -793,7 +810,7 @@ namespace MediaBrowser.Server.Startup.Common
SessionManager.AddParts(GetExports<ISessionControllerFactory>());
- ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());
+ ChannelManager.AddParts(GetExports<IChannel>());
MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
@@ -851,9 +868,9 @@ namespace MediaBrowser.Server.Startup.Common
if (generateCertificate)
{
- if (!File.Exists(certPath))
+ if (!FileSystemManager.FileExists(certPath))
{
- Directory.CreateDirectory(Path.GetDirectoryName(certPath));
+ FileSystemManager.CreateDirectory(Path.GetDirectoryName(certPath));
try
{
@@ -933,7 +950,7 @@ namespace MediaBrowser.Server.Startup.Common
Logger.ErrorException("Error sending server restart notification", ex);
}
- Logger.Debug("Calling NativeApp.Restart");
+ Logger.Info("Calling NativeApp.Restart");
NativeApp.Restart(_startupOptions);
}
@@ -1067,7 +1084,7 @@ namespace MediaBrowser.Server.Startup.Common
SupportsRunningAsService = SupportsRunningAsService,
ServerName = FriendlyName,
LocalAddress = LocalApiUrl,
- SupportsSync = true
+ SupportsLibraryMonitor = SupportsLibraryMonitor
};
}
diff --git a/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs b/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
index 3eeb072a8..a4504f25a 100644
--- a/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
+++ b/MediaBrowser.Server.Startup.Common/Browser/BrowserLauncher.cs
@@ -24,15 +24,6 @@ namespace MediaBrowser.Server.Startup.Common.Browser
}
/// <summary>
- /// Opens the github.
- /// </summary>
- /// <param name="logger">The logger.</param>
- public static void OpenGithub(ILogger logger)
- {
- OpenUrl("https://github.com/MediaBrowser/MediaBrowser", logger);
- }
-
- /// <summary>
/// Opens the community.
/// </summary>
/// <param name="logger">The logger.</param>
@@ -62,18 +53,6 @@ namespace MediaBrowser.Server.Startup.Common.Browser
}
/// <summary>
- /// Opens the swagger.
- /// </summary>
- /// <param name="appHost">The app host.</param>
- /// <param name="logger">The logger.</param>
- public static void OpenSwagger(IServerApplicationHost appHost, ILogger logger)
- {
- var url = appHost.GetLocalApiUrl("localhost") + "/swagger-ui/index.html";
-
- OpenUrl(url, logger);
- }
-
- /// <summary>
/// Opens the URL.
/// </summary>
/// <param name="url">The URL.</param>
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs
index 2910479ef..42fc73488 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs
@@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
case OperatingSystem.Linux:
info.ArchiveType = "7z";
- info.Version = "20150717";
+ info.Version = "20150917";
break;
case OperatingSystem.Osx:
@@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
switch (environment.SystemArchitecture)
{
case Architecture.X86_X64:
- info.Version = "20150827";
+ info.Version = "20150917";
break;
case Architecture.X86:
info.Version = "20150110";
@@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
info.FFMpegFilename = "ffmpeg.exe";
info.FFProbeFilename = "ffprobe.exe";
- info.Version = "20150717";
+ info.Version = "20150918";
info.ArchiveType = "7z";
switch (environment.SystemArchitecture)
@@ -83,14 +83,14 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
case Architecture.X86_X64:
return new[]
{
- "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150717-git-8250943-win64-static.7z",
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150901-git-b54e03c-win64-static.7z"
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150918-win64.7z",
+ "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150916-git-cbbd906-win64-static.7z"
};
case Architecture.X86:
return new[]
{
- "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150717-git-8250943-win32-static.7z",
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150901-git-b54e03c-win32-static.7z"
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20150918-win32.7z",
+ "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150916-git-cbbd906-win32-static.7z"
};
}
break;
@@ -102,7 +102,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
case Architecture.X86_X64:
return new[]
{
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.7.2.7z"
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.8.0.7z"
};
case Architecture.X86:
return new[]
@@ -119,12 +119,12 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
case Architecture.X86_X64:
return new[]
{
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.7.1-64bit-static.7z"
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.8.0-64bit-static.7z"
};
case Architecture.X86:
return new[]
{
- "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.7.1-32bit-static.7z"
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-2.8.0-32bit-static.7z"
};
}
break;
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs
index fe7cd943a..00df7593b 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs
@@ -12,6 +12,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
@@ -78,11 +79,11 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
Version = version
};
- Directory.CreateDirectory(versionedDirectoryPath);
+ _fileSystem.CreateDirectory(versionedDirectoryPath);
var excludeFromDeletions = new List<string> { versionedDirectoryPath };
- if (!File.Exists(info.ProbePath) || !File.Exists(info.EncoderPath))
+ if (!_fileSystem.FileExists(info.ProbePath) || !_fileSystem.FileExists(info.EncoderPath))
{
// ffmpeg not present. See if there's an older version we can start with
var existingVersion = GetExistingVersion(info, rootEncoderPath);
@@ -218,7 +219,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
var tempFolder = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString());
- Directory.CreateDirectory(tempFolder);
+ _fileSystem.CreateDirectory(tempFolder);
try
{
@@ -237,7 +238,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
}))
{
var targetFile = Path.Combine(targetFolder, Path.GetFileName(file));
- File.Copy(file, targetFile, true);
+ _fileSystem.CopyFile(file, targetFile, true);
SetFilePermissions(targetFile);
}
}
@@ -301,13 +302,13 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
var fontsDirectory = Path.Combine(targetPath, "fonts");
- Directory.CreateDirectory(fontsDirectory);
+ _fileSystem.CreateDirectory(fontsDirectory);
const string fontFilename = "ARIALUNI.TTF";
var fontFile = Path.Combine(fontsDirectory, fontFilename);
- if (File.Exists(fontFile))
+ if (_fileSystem.FileExists(fontFile))
{
await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
}
@@ -350,7 +351,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
try
{
- File.Copy(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
+ _fileSystem.CopyFile(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
return;
}
catch (IOException ex)
@@ -412,7 +413,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
const string fontConfigFilename = "fonts.conf";
var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
- if (!File.Exists(fontConfigFile))
+ if (!_fileSystem.FileExists(fontConfigFile))
{
var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
index 124a7f74b..5c3ada82b 100644
--- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
+++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs
@@ -6,6 +6,9 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
+using MediaBrowser.Common.IO;
+using System.Collections.Generic;
+using CommonIO;
namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
@@ -13,78 +16,74 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
private readonly ILogger _logger;
private readonly IApplicationPaths _appPaths;
+ private readonly IFileSystem _fileSystem;
- public FFmpegValidator(ILogger logger, IApplicationPaths appPaths)
+ public FFmpegValidator(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem)
{
_logger = logger;
_appPaths = appPaths;
+ _fileSystem = fileSystem;
}
- public void Validate(FFMpegInfo info)
+ public Tuple<List<string>,List<string>> Validate(FFMpegInfo info)
{
_logger.Info("FFMpeg: {0}", info.EncoderPath);
_logger.Info("FFProbe: {0}", info.ProbePath);
- string cacheKey;
+ var decoders = GetDecoders(info.EncoderPath);
+ var encoders = GetEncoders(info.EncoderPath);
- try
- {
- cacheKey = new FileInfo(info.EncoderPath).Length.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N");
- }
- catch (IOException)
- {
- // This could happen if ffmpeg is coming from a Path variable and we don't have the full path
- cacheKey = Guid.NewGuid().ToString("N");
- }
- catch
- {
- cacheKey = Guid.NewGuid().ToString("N");
- }
-
- var cachePath = Path.Combine(_appPaths.CachePath, "1" + cacheKey);
-
- ValidateCodecs(info.EncoderPath, cachePath);
+ return new Tuple<List<string>, List<string>>(decoders, encoders);
}
- private void ValidateCodecs(string ffmpegPath, string cachePath)
+ private List<string> GetDecoders(string ffmpegPath)
{
- string output = null;
+ string output = string.Empty;
try
{
- output = File.ReadAllText(cachePath, Encoding.UTF8);
+ output = GetFFMpegOutput(ffmpegPath, "-decoders");
}
catch
{
-
}
- if (string.IsNullOrWhiteSpace(output))
+ var found = new List<string>();
+ var required = new[]
{
- try
- {
- output = GetFFMpegOutput(ffmpegPath, "-encoders");
- }
- catch
- {
- return;
- }
+ "h264_qsv",
+ "mpeg2_qsv",
+ "vc1_qsv"
+ };
- try
+ foreach (var codec in required)
+ {
+ var srch = " " + codec + " ";
+
+ if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
{
- Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
- File.WriteAllText(cachePath, output, Encoding.UTF8);
+ _logger.Warn("ffmpeg is missing decoder " + codec);
}
- catch
+ else
{
-
+ found.Add(codec);
}
}
- ValidateCodecsFromOutput(output);
+ return found;
}
- private void ValidateCodecsFromOutput(string output)
+ private List<string> GetEncoders(string ffmpegPath)
{
+ string output = null;
+ try
+ {
+ output = GetFFMpegOutput(ffmpegPath, "-encoders");
+ }
+ catch
+ {
+ }
+
+ var found = new List<string>();
var required = new[]
{
"libx264",
@@ -100,16 +99,21 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg
"srt"
};
- foreach (var encoder in required)
+ foreach (var codec in required)
{
- var srch = " " + encoder + " ";
+ var srch = " " + codec + " ";
if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
{
- _logger.Error("ffmpeg is missing encoder " + encoder);
- //throw new ArgumentException("ffmpeg is missing encoder " + encoder);
+ _logger.Warn("ffmpeg is missing encoder " + codec);
+ }
+ else
+ {
+ found.Add(codec);
}
}
+
+ return found;
}
private string GetFFMpegOutput(string path, string arguments)
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 01bc069a7..597caf34c 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/MediaBrowser.Server.Startup.Common/INativeApp.cs
@@ -53,6 +53,12 @@ namespace MediaBrowser.Server.Startup.Common
bool SupportsAutoRunAtStartup { get; }
/// <summary>
+ /// Gets a value indicating whether [supports library monitor].
+ /// </summary>
+ /// <value><c>true</c> if [supports library monitor]; otherwise, <c>false</c>.</value>
+ bool SupportsLibraryMonitor { get; }
+
+ /// <summary>
/// Gets a value indicating whether this instance can self update.
/// </summary>
/// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
diff --git a/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs b/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs
new file mode 100644
index 000000000..14588b427
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/MbLinkShortcutHandler.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+using CommonIO;
+
+namespace MediaBrowser.Server.Startup.Common
+{
+ public class MbLinkShortcutHandler : IShortcutHandler
+ {
+ private readonly IFileSystem _fileSystem;
+
+ public MbLinkShortcutHandler(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
+ public string Extension
+ {
+ get { return ".mblink"; }
+ }
+
+ public string Resolve(string shortcutPath)
+ {
+ if (string.IsNullOrEmpty(shortcutPath))
+ {
+ throw new ArgumentNullException("filenshortcutPathame");
+ }
+
+ if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase))
+ {
+ var path = _fileSystem.ReadAllText(shortcutPath);
+
+ return _fileSystem.NormalizePath(path);
+ }
+
+ return null;
+ }
+
+ public void Create(string shortcutPath, string targetPath)
+ {
+ if (string.IsNullOrEmpty(shortcutPath))
+ {
+ throw new ArgumentNullException("shortcutPath");
+ }
+
+ if (string.IsNullOrEmpty(targetPath))
+ {
+ throw new ArgumentNullException("targetPath");
+ }
+
+ File.WriteAllText(shortcutPath, targetPath);
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index 4653e6ac7..13b782e40 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -12,7 +12,6 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,10 +31,18 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="Mono.Posix, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
</Reference>
+ <Reference Include="Patterns.Logging, Version=1.0.5494.41209, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="ServiceStack.Interfaces, Version=4.0.0.0, Culture=neutral, PublicKeyToken=e06fbc6124f57c43, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
@@ -63,11 +70,9 @@
<Compile Include="FFMpeg\FFMpegInfo.cs" />
<Compile Include="FFMpeg\FFmpegValidator.cs" />
<Compile Include="INativeApp.cs" />
- <Compile Include="Migrations\DeleteDlnaProfiles.cs" />
- <Compile Include="Migrations\DeprecatePlugins.cs" />
+ <Compile Include="MbLinkShortcutHandler.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
- <Compile Include="Migrations\MigrateUserFolders.cs" />
- <Compile Include="Migrations\RenameXbmcOptions.cs" />
+ <Compile Include="Migrations\Release5767.cs" />
<Compile Include="Migrations\RenameXmlOptions.cs" />
<Compile Include="NativeEnvironment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs b/MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs
deleted file mode 100644
index 166c2627f..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/DeleteDlnaProfiles.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using System.IO;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class DeleteDlnaProfiles : IVersionMigration
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
-
- public DeleteDlnaProfiles(IServerApplicationPaths appPaths, IFileSystem fileSystem)
- {
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- }
-
- public void Run()
- {
- RemoveProfile("Android");
- RemoveProfile("Windows Phone");
- RemoveProfile("Windows 8 RT");
- }
-
- private void RemoveProfile(string filename)
- {
- try
- {
- _fileSystem.DeleteFile(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system", filename + ".xml"));
- }
- catch
- {
-
- }
- try
- {
- _fileSystem.DeleteFile(Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user", filename + ".xml"));
- }
- catch
- {
-
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs b/MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs
deleted file mode 100644
index afdd4e623..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/DeprecatePlugins.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using System.IO;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class DeprecatePlugins : IVersionMigration
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
-
- public DeprecatePlugins(IServerApplicationPaths appPaths, IFileSystem fileSystem)
- {
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- }
-
- public void Run()
- {
- RemovePlugin("MediaBrowser.Plugins.LocalTrailers.dll");
- }
-
- private void RemovePlugin(string filename)
- {
- try
- {
- _fileSystem.DeleteFile(Path.Combine(_appPaths.PluginsPath, filename));
- }
- catch
- {
-
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs b/MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs
deleted file mode 100644
index cb566d6cf..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/MigrateUserFolders.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using System;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class MigrateUserFolders : IVersionMigration
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
-
- public MigrateUserFolders(IServerApplicationPaths appPaths, IFileSystem fileSystem)
- {
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- }
-
- public void Run()
- {
- try
- {
- var rootPath = _appPaths.RootFolderPath;
-
- var folders = new DirectoryInfo(rootPath).EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Where(i => !string.Equals(i.Name, "default", StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- foreach (var folder in folders)
- {
- _fileSystem.DeleteDirectory(folder.FullName, true);
- }
- }
- catch (IOException)
- {
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs b/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs
new file mode 100644
index 000000000..168230b87
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Server.Implementations.LiveTv;
+using MediaBrowser.Server.Implementations.Persistence;
+using MediaBrowser.Server.Implementations.ScheduledTasks;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+ public class Release5767 : IVersionMigration
+ {
+ private readonly IServerConfigurationManager _config;
+ private readonly ITaskManager _taskManager;
+
+ public Release5767(IServerConfigurationManager config, ITaskManager taskManager)
+ {
+ _config = config;
+ _taskManager = taskManager;
+ }
+
+ public async void Run()
+ {
+ var name = "5767.1";
+
+ if (_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase))
+ {
+ return;
+ }
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(3000).ConfigureAwait(false);
+
+ _taskManager.QueueScheduledTask<CleanDatabaseScheduledTask>();
+ });
+
+ // Wait a few minutes before marking this as done. Make sure the server doesn't get restarted.
+ await Task.Delay(300000).ConfigureAwait(false);
+
+ var list = _config.Configuration.Migrations.ToList();
+ list.Add(name);
+ _config.Configuration.Migrations = list.ToArray();
+ _config.SaveConfiguration();
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXbmcOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXbmcOptions.cs
deleted file mode 100644
index 02b0f9a0a..000000000
--- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXbmcOptions.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using System;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
- public class RenameXbmcOptions : IVersionMigration
- {
- private readonly IServerConfigurationManager _config;
-
- public RenameXbmcOptions(IServerConfigurationManager config)
- {
- _config = config;
- }
-
- public void Run()
- {
- var changed = false;
-
- foreach (var option in _config.Configuration.MetadataOptions)
- {
- if (Migrate(option.DisabledMetadataSavers))
- {
- changed = true;
- }
- if (Migrate(option.LocalMetadataReaderOrder))
- {
- changed = true;
- }
- }
-
- if (changed)
- {
- _config.SaveConfiguration();
- }
- }
-
- private bool Migrate(string[] options)
- {
- var changed = false;
-
- if (options != null)
- {
- for (var i = 0; i < options.Length; i++)
- {
- if (string.Equals(options[i], "Xbmc Nfo", StringComparison.OrdinalIgnoreCase))
- {
- options[i] = "Nfo";
- changed = true;
- }
- }
- }
-
- return changed;
- }
- }
-}
diff --git a/MediaBrowser.Server.Startup.Common/UnhandledExceptionWriter.cs b/MediaBrowser.Server.Startup.Common/UnhandledExceptionWriter.cs
index 96c24eaab..804533b9d 100644
--- a/MediaBrowser.Server.Startup.Common/UnhandledExceptionWriter.cs
+++ b/MediaBrowser.Server.Startup.Common/UnhandledExceptionWriter.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Server.Startup.Common
_logManager.Flush();
var path = Path.Combine(_appPaths.LogDirectoryPath, "unhandled_" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
var builder = LogHelper.GetLogMessage(ex);
@@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Startup.Common
Console.WriteLine("UnhandledException");
Console.WriteLine(builder.ToString());
- File.WriteAllText(path, builder.ToString());
+ File.WriteAllText(path, builder.ToString());
}
}
}
diff --git a/MediaBrowser.Server.Startup.Common/packages.config b/MediaBrowser.Server.Startup.Common/packages.config
index 120360cd4..6a2a6c1e5 100644
--- a/MediaBrowser.Server.Startup.Common/packages.config
+++ b/MediaBrowser.Server.Startup.Common/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index d7b8b2aed..b8af35fde 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -17,6 +17,8 @@ using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
+using CommonIO.Windows;
+using MediaBrowser.Server.Implementations.Logging;
namespace MediaBrowser.ServerApplication
{
@@ -201,7 +203,8 @@ namespace MediaBrowser.ServerApplication
/// <param name="options">The options.</param>
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, bool runService, StartupOptions options)
{
- var fileSystem = new NativeFileSystem(logManager.GetLogger("FileSystem"), false);
+ var fileSystem = new WindowsFileSystem(new PatternsLogger(logManager.GetLogger("FileSystem")));
+ fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
var nativeApp = new WindowsApp(fileSystem)
{
@@ -327,11 +330,6 @@ namespace MediaBrowser.ServerApplication
_logger.Info("Shutting down");
_appHost.Dispose();
-
- if (!_isRunningAsService)
- {
- SetErrorMode(ErrorModes.SYSTEM_DEFAULT);
- }
}
/// <summary>
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index c0830c8c9..3b4b52af3 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -12,7 +12,6 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -23,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -60,12 +60,20 @@
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
<Reference Include="ImageMagickSharp">
<HintPath>..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference>
<Reference Include="MediaBrowser.IsoMounter">
<HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>
</Reference>
+ <Reference Include="Patterns.Logging, Version=1.0.5494.41209, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="pfmclrapi">
<HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\pfmclrapi.dll</HintPath>
</Reference>
@@ -99,7 +107,6 @@
<Compile Include="BackgroundServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
- <Compile Include="Native\NativeFileSystem.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -469,11 +476,4 @@
</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')" />
- <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
- <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
- <PropertyGroup>
- <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable 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('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
- </Target>
</Project> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Native/Autorun.cs b/MediaBrowser.ServerApplication/Native/Autorun.cs
index dd2a77565..2cacaae8e 100644
--- a/MediaBrowser.ServerApplication/Native/Autorun.cs
+++ b/MediaBrowser.ServerApplication/Native/Autorun.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Common.IO;
using System;
using System.IO;
+using CommonIO;
namespace MediaBrowser.ServerApplication.Native
{
diff --git a/MediaBrowser.ServerApplication/Native/NativeFileSystem.cs b/MediaBrowser.ServerApplication/Native/NativeFileSystem.cs
deleted file mode 100644
index 90ebe7e2d..000000000
--- a/MediaBrowser.ServerApplication/Native/NativeFileSystem.cs
+++ /dev/null
@@ -1,419 +0,0 @@
-using MediaBrowser.Common.Implementations.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Text;
-
-namespace MediaBrowser.ServerApplication.Native
-{
- public class NativeFileSystem : CommonFileSystem
- {
- public NativeFileSystem(ILogger logger, bool usePresetInvalidFileNameChars)
- : base(logger, true, usePresetInvalidFileNameChars)
- {
- }
-
- public override bool IsShortcut(string filename)
- {
- return base.IsShortcut(filename) ||
- string.Equals(Path.GetExtension(filename), ".lnk", StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ResolveShortcut(string filename)
- {
- var path = base.ResolveShortcut(filename);
-
- if (!string.IsNullOrEmpty(path))
- {
- return path;
- }
-
- if (string.Equals(Path.GetExtension(filename), ".lnk", StringComparison.OrdinalIgnoreCase))
- {
- return ResolveLnk(filename);
- }
-
- return null;
- }
-
- private string ResolveLnk(string filename)
- {
- var link = new ShellLink();
- ((IPersistFile)link).Load(filename, NativeMethods.STGM_READ);
- // ((IShellLinkW)link).Resolve(hwnd, 0)
- var sb = new StringBuilder(NativeMethods.MAX_PATH);
- WIN32_FIND_DATA data;
- ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0);
- return sb.ToString();
- }
- }
-
- /// <summary>
- /// Class NativeMethods
- /// </summary>
- [SuppressUnmanagedCodeSecurity]
- public static class NativeMethods
- {
- /// <summary>
- /// The MA x_ PATH
- /// </summary>
- public const int MAX_PATH = 260;
- /// <summary>
- /// The MA x_ ALTERNATE
- /// </summary>
- public const int MAX_ALTERNATE = 14;
- /// <summary>
- /// The INVALI d_ HANDL e_ VALUE
- /// </summary>
- public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
- /// <summary>
- /// The STG m_ READ
- /// </summary>
- public const uint STGM_READ = 0;
- }
-
- /// <summary>
- /// Struct FILETIME
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- public struct FILETIME
- {
- /// <summary>
- /// The dw low date time
- /// </summary>
- public uint dwLowDateTime;
- /// <summary>
- /// The dw high date time
- /// </summary>
- public uint dwHighDateTime;
- }
-
- /// <summary>
- /// Struct WIN32_FIND_DATA
- /// </summary>
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct WIN32_FIND_DATA
- {
- /// <summary>
- /// The dw file attributes
- /// </summary>
- public FileAttributes dwFileAttributes;
- /// <summary>
- /// The ft creation time
- /// </summary>
- public FILETIME ftCreationTime;
- /// <summary>
- /// The ft last access time
- /// </summary>
- public FILETIME ftLastAccessTime;
- /// <summary>
- /// The ft last write time
- /// </summary>
- public FILETIME ftLastWriteTime;
- /// <summary>
- /// The n file size high
- /// </summary>
- public int nFileSizeHigh;
- /// <summary>
- /// The n file size low
- /// </summary>
- public int nFileSizeLow;
- /// <summary>
- /// The dw reserved0
- /// </summary>
- public int dwReserved0;
- /// <summary>
- /// The dw reserved1
- /// </summary>
- public int dwReserved1;
-
- /// <summary>
- /// The c file name
- /// </summary>
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeMethods.MAX_PATH)]
- public string cFileName;
-
- /// <summary>
- /// This will always be null when FINDEX_INFO_LEVELS = basic
- /// </summary>
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeMethods.MAX_ALTERNATE)]
- public string cAlternate;
-
- /// <summary>
- /// Gets or sets the path.
- /// </summary>
- /// <value>The path.</value>
- public string Path { get; set; }
-
- /// <summary>
- /// Returns a <see cref="System.String" /> that represents this instance.
- /// </summary>
- /// <returns>A <see cref="System.String" /> that represents this instance.</returns>
- public override string ToString()
- {
- return Path ?? string.Empty;
- }
- }
-
- /// <summary>
- /// Enum SLGP_FLAGS
- /// </summary>
- [Flags]
- public enum SLGP_FLAGS
- {
- /// <summary>
- /// Retrieves the standard short (8.3 format) file name
- /// </summary>
- SLGP_SHORTPATH = 0x1,
- /// <summary>
- /// Retrieves the Universal Naming Convention (UNC) path name of the file
- /// </summary>
- SLGP_UNCPRIORITY = 0x2,
- /// <summary>
- /// Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded
- /// </summary>
- SLGP_RAWPATH = 0x4
- }
- /// <summary>
- /// Enum SLR_FLAGS
- /// </summary>
- [Flags]
- public enum SLR_FLAGS
- {
- /// <summary>
- /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set,
- /// the high-order word of fFlags can be set to a time-out value that specifies the
- /// maximum amount of time to be spent resolving the link. The function returns if the
- /// link cannot be resolved within the time-out duration. If the high-order word is set
- /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds
- /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out
- /// duration, in milliseconds.
- /// </summary>
- SLR_NO_UI = 0x1,
- /// <summary>
- /// Obsolete and no longer used
- /// </summary>
- SLR_ANY_MATCH = 0x2,
- /// <summary>
- /// If the link object has changed, update its path and list of identifiers.
- /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine
- /// whether or not the link object has changed.
- /// </summary>
- SLR_UPDATE = 0x4,
- /// <summary>
- /// Do not update the link information
- /// </summary>
- SLR_NOUPDATE = 0x8,
- /// <summary>
- /// Do not execute the search heuristics
- /// </summary>
- SLR_NOSEARCH = 0x10,
- /// <summary>
- /// Do not use distributed link tracking
- /// </summary>
- SLR_NOTRACK = 0x20,
- /// <summary>
- /// Disable distributed link tracking. By default, distributed link tracking tracks
- /// removable media across multiple devices based on the volume name. It also uses the
- /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter
- /// has changed. Setting SLR_NOLINKINFO disables both types of tracking.
- /// </summary>
- SLR_NOLINKINFO = 0x40,
- /// <summary>
- /// Call the Microsoft Windows Installer
- /// </summary>
- SLR_INVOKE_MSI = 0x80
- }
-
- /// <summary>
- /// The IShellLink interface allows Shell links to be created, modified, and resolved
- /// </summary>
- [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
- public interface IShellLinkW
- {
- /// <summary>
- /// Retrieves the path and file name of a Shell link object
- /// </summary>
- /// <param name="pszFile">The PSZ file.</param>
- /// <param name="cchMaxPath">The CCH max path.</param>
- /// <param name="pfd">The PFD.</param>
- /// <param name="fFlags">The f flags.</param>
- void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATA pfd, SLGP_FLAGS fFlags);
- /// <summary>
- /// Retrieves the list of item identifiers for a Shell link object
- /// </summary>
- /// <param name="ppidl">The ppidl.</param>
- void GetIDList(out IntPtr ppidl);
- /// <summary>
- /// Sets the pointer to an item identifier list (PIDL) for a Shell link object.
- /// </summary>
- /// <param name="pidl">The pidl.</param>
- void SetIDList(IntPtr pidl);
- /// <summary>
- /// Retrieves the description string for a Shell link object
- /// </summary>
- /// <param name="pszName">Name of the PSZ.</param>
- /// <param name="cchMaxName">Name of the CCH max.</param>
- void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
- /// <summary>
- /// Sets the description for a Shell link object. The description can be any application-defined string
- /// </summary>
- /// <param name="pszName">Name of the PSZ.</param>
- void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- /// <summary>
- /// Retrieves the name of the working directory for a Shell link object
- /// </summary>
- /// <param name="pszDir">The PSZ dir.</param>
- /// <param name="cchMaxPath">The CCH max path.</param>
- void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
- /// <summary>
- /// Sets the name of the working directory for a Shell link object
- /// </summary>
- /// <param name="pszDir">The PSZ dir.</param>
- void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- /// <summary>
- /// Retrieves the command-line arguments associated with a Shell link object
- /// </summary>
- /// <param name="pszArgs">The PSZ args.</param>
- /// <param name="cchMaxPath">The CCH max path.</param>
- void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
- /// <summary>
- /// Sets the command-line arguments for a Shell link object
- /// </summary>
- /// <param name="pszArgs">The PSZ args.</param>
- void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- /// <summary>
- /// Retrieves the hot key for a Shell link object
- /// </summary>
- /// <param name="pwHotkey">The pw hotkey.</param>
- void GetHotkey(out short pwHotkey);
- /// <summary>
- /// Sets a hot key for a Shell link object
- /// </summary>
- /// <param name="wHotkey">The w hotkey.</param>
- void SetHotkey(short wHotkey);
- /// <summary>
- /// Retrieves the show command for a Shell link object
- /// </summary>
- /// <param name="piShowCmd">The pi show CMD.</param>
- void GetShowCmd(out int piShowCmd);
- /// <summary>
- /// Sets the show command for a Shell link object. The show command sets the initial show state of the window.
- /// </summary>
- /// <param name="iShowCmd">The i show CMD.</param>
- void SetShowCmd(int iShowCmd);
- /// <summary>
- /// Retrieves the location (path and index) of the icon for a Shell link object
- /// </summary>
- /// <param name="pszIconPath">The PSZ icon path.</param>
- /// <param name="cchIconPath">The CCH icon path.</param>
- /// <param name="piIcon">The pi icon.</param>
- void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- /// <summary>
- /// Sets the location (path and index) of the icon for a Shell link object
- /// </summary>
- /// <param name="pszIconPath">The PSZ icon path.</param>
- /// <param name="iIcon">The i icon.</param>
- void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- /// <summary>
- /// Sets the relative path to the Shell link object
- /// </summary>
- /// <param name="pszPathRel">The PSZ path rel.</param>
- /// <param name="dwReserved">The dw reserved.</param>
- void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
- /// <summary>
- /// Attempts to find the target of a Shell link, even if it has been moved or renamed
- /// </summary>
- /// <param name="hwnd">The HWND.</param>
- /// <param name="fFlags">The f flags.</param>
- void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
- /// <summary>
- /// Sets the path and file name of a Shell link object
- /// </summary>
- /// <param name="pszFile">The PSZ file.</param>
- void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
-
- }
-
- /// <summary>
- /// Interface IPersist
- /// </summary>
- [ComImport, Guid("0000010c-0000-0000-c000-000000000046"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IPersist
- {
- /// <summary>
- /// Gets the class ID.
- /// </summary>
- /// <param name="pClassID">The p class ID.</param>
- [PreserveSig]
- void GetClassID(out Guid pClassID);
- }
-
- /// <summary>
- /// Interface IPersistFile
- /// </summary>
- [ComImport, Guid("0000010b-0000-0000-C000-000000000046"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IPersistFile : IPersist
- {
- /// <summary>
- /// Gets the class ID.
- /// </summary>
- /// <param name="pClassID">The p class ID.</param>
- new void GetClassID(out Guid pClassID);
- /// <summary>
- /// Determines whether this instance is dirty.
- /// </summary>
- [PreserveSig]
- int IsDirty();
-
- /// <summary>
- /// Loads the specified PSZ file name.
- /// </summary>
- /// <param name="pszFileName">Name of the PSZ file.</param>
- /// <param name="dwMode">The dw mode.</param>
- [PreserveSig]
- void Load([In, MarshalAs(UnmanagedType.LPWStr)]
- string pszFileName, uint dwMode);
-
- /// <summary>
- /// Saves the specified PSZ file name.
- /// </summary>
- /// <param name="pszFileName">Name of the PSZ file.</param>
- /// <param name="remember">if set to <c>true</c> [remember].</param>
- [PreserveSig]
- void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
- [In, MarshalAs(UnmanagedType.Bool)] bool remember);
-
- /// <summary>
- /// Saves the completed.
- /// </summary>
- /// <param name="pszFileName">Name of the PSZ file.</param>
- [PreserveSig]
- void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
-
- /// <summary>
- /// Gets the cur file.
- /// </summary>
- /// <param name="ppszFileName">Name of the PPSZ file.</param>
- [PreserveSig]
- void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName);
- }
-
- // CLSID_ShellLink from ShlGuid.h
- /// <summary>
- /// Class ShellLink
- /// </summary>
- [
- ComImport,
- Guid("00021401-0000-0000-C000-000000000046")
- ]
- public class ShellLink
- {
- }
-
-}
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index bad1aaf35..bff342d01 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -1,11 +1,11 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
using MediaBrowser.IsoMounter;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Startup.Common;
using MediaBrowser.ServerApplication.Networking;
using System.Collections.Generic;
using System.Reflection;
+using CommonIO;
namespace MediaBrowser.ServerApplication.Native
{
@@ -22,7 +22,10 @@ namespace MediaBrowser.ServerApplication.Native
{
var list = new List<Assembly>();
- list.Add(typeof(PismoIsoManager).Assembly);
+ if (!System.Environment.Is64BitProcess)
+ {
+ list.Add(typeof(PismoIsoManager).Assembly);
+ }
list.Add(GetType().Assembly);
@@ -47,6 +50,11 @@ namespace MediaBrowser.ServerApplication.Native
}
}
+ public bool SupportsLibraryMonitor
+ {
+ get { return true; }
+ }
+
public bool SupportsRunningAsService
{
get
diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
index ad0bd8a1a..e9a7d5985 100644
--- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
+++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.ServerApplication
public class ServerNotifyIcon : IDisposable
{
bool IsDisposing = false;
-
+
private NotifyIcon notifyIcon1;
private ContextMenuStrip contextMenuStrip1;
private ToolStripMenuItem cmdExit;
@@ -21,9 +21,6 @@ namespace MediaBrowser.ServerApplication
private ToolStripMenuItem cmdRestart;
private ToolStripSeparator toolStripSeparator1;
private ToolStripMenuItem cmdCommunity;
- private ToolStripMenuItem cmdApiDocs;
- private ToolStripMenuItem cmdSwagger;
- private ToolStripMenuItem cmdGtihub;
private readonly ILogger _logger;
private readonly IServerApplicationHost _appHost;
@@ -43,8 +40,8 @@ namespace MediaBrowser.ServerApplication
}
}
- public ServerNotifyIcon(ILogManager logManager,
- IServerApplicationHost appHost,
+ public ServerNotifyIcon(ILogManager logManager,
+ IServerApplicationHost appHost,
IServerConfigurationManager configurationManager,
ILocalizationManager localization)
{
@@ -52,13 +49,13 @@ namespace MediaBrowser.ServerApplication
_localization = localization;
_appHost = appHost;
_configurationManager = configurationManager;
-
+
var components = new System.ComponentModel.Container();
-
+
var resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
contextMenuStrip1 = new ContextMenuStrip(components);
notifyIcon1 = new NotifyIcon(components);
-
+
cmdExit = new ToolStripMenuItem();
cmdCommunity = new ToolStripMenuItem();
toolStripSeparator1 = new ToolStripSeparator();
@@ -66,10 +63,7 @@ namespace MediaBrowser.ServerApplication
toolStripSeparator2 = new ToolStripSeparator();
cmdConfigure = new ToolStripMenuItem();
cmdBrowse = new ToolStripMenuItem();
- cmdApiDocs = new ToolStripMenuItem();
- cmdSwagger = new ToolStripMenuItem();
- cmdGtihub = new ToolStripMenuItem();
-
+
//
// notifyIcon1
//
@@ -86,7 +80,6 @@ namespace MediaBrowser.ServerApplication
toolStripSeparator2,
cmdRestart,
toolStripSeparator1,
- cmdApiDocs,
cmdCommunity,
cmdExit});
contextMenuStrip1.Name = "contextMenuStrip1";
@@ -128,24 +121,6 @@ namespace MediaBrowser.ServerApplication
//
cmdBrowse.Name = "cmdBrowse";
cmdBrowse.Size = new System.Drawing.Size(208, 22);
- //
- // cmdApiDocs
- //
- cmdApiDocs.DropDownItems.AddRange(new ToolStripItem[] {
- cmdSwagger,
- cmdGtihub});
- cmdApiDocs.Name = "cmdApiDocs";
- cmdApiDocs.Size = new System.Drawing.Size(208, 22);
- //
- // cmdSwagger
- //
- cmdSwagger.Name = "cmdSwagger";
- cmdSwagger.Size = new System.Drawing.Size(136, 22);
- //
- // cmdGtihub
- //
- cmdGtihub.Name = "cmdGtihub";
- cmdGtihub.Size = new System.Drawing.Size(136, 22);
cmdExit.Click += cmdExit_Click;
cmdRestart.Click += cmdRestart_Click;
@@ -153,20 +128,10 @@ namespace MediaBrowser.ServerApplication
cmdCommunity.Click += cmdCommunity_Click;
cmdBrowse.Click += cmdBrowse_Click;
- cmdSwagger.Click += cmdSwagger_Click;
- cmdGtihub.Click += cmdGtihub_Click;
-
_configurationManager.ConfigurationUpdated += Instance_ConfigurationUpdated;
LocalizeText();
- if (_appHost.IsFirstRun)
- {
- Action action = () => notifyIcon1.ShowBalloonTip(5000, "Emby", "Welcome to Emby Server!", ToolTipIcon.Info);
-
- contextMenuStrip1.Invoke(action);
- }
-
notifyIcon1.DoubleClick += notifyIcon1_DoubleClick;
Application.ApplicationExit += Application_ApplicationExit;
}
@@ -194,9 +159,6 @@ namespace MediaBrowser.ServerApplication
cmdExit.Text = _localization.GetLocalizedString("LabelExit");
cmdCommunity.Text = _localization.GetLocalizedString("LabelVisitCommunity");
- cmdGtihub.Text = _localization.GetLocalizedString("LabelGithub");
- cmdSwagger.Text = _localization.GetLocalizedString("LabelApiDocumentation");
- cmdApiDocs.Text = _localization.GetLocalizedString("LabelDeveloperResources");
cmdBrowse.Text = _localization.GetLocalizedString("LabelBrowseLibrary");
cmdConfigure.Text = _localization.GetLocalizedString("LabelConfigureServer");
cmdRestart.Text = _localization.GetLocalizedString("LabelRestartServer");
@@ -242,16 +204,6 @@ namespace MediaBrowser.ServerApplication
_appHost.Shutdown();
}
- void cmdGtihub_Click(object sender, EventArgs e)
- {
- BrowserLauncher.OpenGithub(_logger);
- }
-
- void cmdSwagger_Click(object sender, EventArgs e)
- {
- BrowserLauncher.OpenSwagger(_appHost, _logger);
- }
-
~ServerNotifyIcon()
{
Dispose();
@@ -265,4 +217,4 @@ namespace MediaBrowser.ServerApplication
}
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 5007cf8af..dec8199cc 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="ImageMagickSharp" version="1.0.0.16" targetFramework="net45" />
<package id="MediaBrowser.IsoMounting" version="3.0.69" 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" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/unit.srt b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/unit.srt
index 5f6e5636e..1ce811bcb 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/unit.srt
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/unit.srt
@@ -35,7 +35,7 @@ Unclosed but <b>supported HTML tags are left in, {\i1} SSA italics aren't
9
00:00:36,000 --> 00:00:36,999
-Multiple {\pos(142,120)\b1}SSA tags are stripped
+Multiple {\bord-3.7\clip(1,m 50 0 b 100 0 100 100 50 100 b 0 100 0 0 50 0)\pos(142,120)\t(0,500,\fscx100\fscy100)\b1\c&H000000&}SSA tags are stripped
10
00:00:37,000 --> 00:00:37,999
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 69c4417cb..030dc7f33 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using CommonIO;
using WebMarkupMin.Core.Minifiers;
namespace MediaBrowser.WebDashboard.Api
@@ -274,8 +275,8 @@ namespace MediaBrowser.WebDashboard.Api
private void CopyFile(string src, string dst)
{
- Directory.CreateDirectory(Path.GetDirectoryName(dst));
- File.Copy(src, dst, true);
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(dst));
+ _fileSystem.CopyFile(src, dst, true);
}
public async Task<object> Get(GetDashboardPackage request)
@@ -306,17 +307,17 @@ namespace MediaBrowser.WebDashboard.Api
{
// Overwrite certain files with cordova specific versions
var cordovaVersion = Path.Combine(path, "cordova", "registrationservices.js");
- File.Copy(cordovaVersion, Path.Combine(path, "scripts", "registrationservices.js"), true);
- File.Delete(cordovaVersion);
+ _fileSystem.CopyFile(cordovaVersion, Path.Combine(path, "scripts", "registrationservices.js"), true);
+ _fileSystem.DeleteFile(cordovaVersion);
// Delete things that are unneeded in an attempt to keep the output as trim as possible
- Directory.Delete(Path.Combine(path, "css", "images", "tour"), true);
- Directory.Delete(Path.Combine(path, "apiclient", "alt"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(path, "css", "images", "tour"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(path, "apiclient", "alt"), true);
- File.Delete(Path.Combine(path, "thirdparty", "jquerymobile-1.4.5", "jquery.mobile-1.4.5.min.map"));
+ _fileSystem.DeleteFile(Path.Combine(path, "thirdparty", "jquerymobile-1.4.5", "jquery.mobile-1.4.5.min.map"));
- Directory.Delete(Path.Combine(path, "bower_components"), true);
- Directory.Delete(Path.Combine(path, "thirdparty", "viblast"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(path, "bower_components"), true);
+ _fileSystem.DeleteDirectory(Path.Combine(path, "thirdparty", "viblast"), true);
// But we do need this
CopyFile(Path.Combine(creator.DashboardUIPath, "bower_components", "webcomponentsjs", "webcomponents-lite.js"), Path.Combine(path, "bower_components", "webcomponentsjs", "webcomponents-lite.js"));
@@ -333,6 +334,8 @@ namespace MediaBrowser.WebDashboard.Api
CopyDirectory(Path.Combine(creator.DashboardUIPath, "bower_components", "swipebox", "src", "img"), Path.Combine(path, "bower_components", "swipebox", "src", "img"));
CopyFile(Path.Combine(creator.DashboardUIPath, "bower_components", "hammerjs", "hammer.min.js"), Path.Combine(path, "bower_components", "hammerjs", "hammer.min.js"));
+
+ CopyFile(Path.Combine(creator.DashboardUIPath, "bower_components", "Sortable", "Sortable.min.js"), Path.Combine(path, "bower_components", "Sortable", "Sortable.min.js"));
}
MinifyCssDirectory(Path.Combine(path, "css"));
@@ -355,7 +358,7 @@ namespace MediaBrowser.WebDashboard.Api
{
try
{
- var text = File.ReadAllText(file, Encoding.UTF8);
+ var text = _fileSystem.ReadAllText(file, Encoding.UTF8);
var result = new KristensenCssMinifier().Minify(text, false, Encoding.UTF8);
@@ -366,7 +369,7 @@ namespace MediaBrowser.WebDashboard.Api
else
{
text = result.MinifiedContent;
- File.WriteAllText(file, text, Encoding.UTF8);
+ _fileSystem.WriteAllText(file, text, Encoding.UTF8);
}
}
catch (Exception ex)
@@ -382,7 +385,7 @@ namespace MediaBrowser.WebDashboard.Api
{
try
{
- var text = File.ReadAllText(file, Encoding.UTF8);
+ var text = _fileSystem.ReadAllText(file, Encoding.UTF8);
var result = new CrockfordJsMinifier().Minify(text, false, Encoding.UTF8);
@@ -393,7 +396,7 @@ namespace MediaBrowser.WebDashboard.Api
else
{
text = result.MinifiedContent;
- File.WriteAllText(file, text, Encoding.UTF8);
+ _fileSystem.WriteAllText(file, text, Encoding.UTF8);
}
}
catch (Exception ex)
@@ -416,13 +419,12 @@ namespace MediaBrowser.WebDashboard.Api
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
- excludeFiles.Add("supporter.html");
excludeFiles.Add("supporterkey.html");
}
foreach (var file in excludeFiles)
{
- File.Delete(Path.Combine(destination, file));
+ _fileSystem.DeleteFile(Path.Combine(destination, file));
}
}
@@ -449,17 +451,17 @@ namespace MediaBrowser.WebDashboard.Api
private void CopyDirectory(string source, string destination)
{
- Directory.CreateDirectory(destination);
+ _fileSystem.CreateDirectory(destination);
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(source, "*",
SearchOption.AllDirectories))
- Directory.CreateDirectory(dirPath.Replace(source, destination));
+ _fileSystem.CreateDirectory(dirPath.Replace(source, destination));
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(source, "*.*",
SearchOption.AllDirectories))
- File.Copy(newPath, newPath.Replace(source, destination), true);
+ _fileSystem.CopyFile(newPath, newPath.Replace(source, destination), true);
}
}
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 48ad62bd4..3108c2b9a 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -9,6 +9,8 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using CommonIO;
+using MediaBrowser.Controller.Net;
using WebMarkupMin.Core;
using WebMarkupMin.Core.Minifiers;
using WebMarkupMin.Core.Settings;
@@ -136,7 +138,7 @@ namespace MediaBrowser.WebDashboard.Api
// Don't allow file system access outside of the source folder
if (!_fileSystem.ContainsSubPath(rootPath, fullPath))
{
- throw new UnauthorizedAccessException();
+ throw new SecurityException("Access denied");
}
return fullPath;
@@ -521,7 +523,6 @@ namespace MediaBrowser.WebDashboard.Api
"thirdparty/jquery.unveil-custom.js",
"apiclient/logger.js",
"apiclient/md5.js",
- "apiclient/sha1.js",
"apiclient/store.js",
"apiclient/device.js",
"apiclient/credentials.js",
@@ -607,10 +608,7 @@ namespace MediaBrowser.WebDashboard.Api
"appsettings.js",
"mediaplayer.js",
"mediaplayer-video.js",
- "nowplayingbar.js",
"alphapicker.js",
- "directorybrowser.js",
- "collectioneditor.js",
"notifications.js",
"remotecontrol.js",
"search.js",
@@ -657,7 +655,6 @@ namespace MediaBrowser.WebDashboard.Api
"thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.structure.css",
"css/site.css",
"css/chromecast.css",
- "css/nowplayingbar.css",
"css/mediaplayer.css",
"css/mediaplayer-video.css",
"css/librarymenu.css",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 8abd591e5..50bad0aa9 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -14,7 +14,6 @@
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -48,6 +47,13 @@
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -57,9 +63,8 @@
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
</Reference>
- <Reference Include="WebMarkupMin.Core, Version=0.9.12.0, Culture=neutral, PublicKeyToken=99472178d266584b, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\WebMarkupMin.Core.0.9.12\lib\net40\WebMarkupMin.Core.dll</HintPath>
+ <Reference Include="WebMarkupMin.Core">
+ <HintPath>..\packages\WebMarkupMin.Core.1.0.0\lib\net40\WebMarkupMin.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -87,6 +92,24 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <Content Include="dashboard-ui\apiclient\sync\contentuploader.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\apiclient\fileupload.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\apiclient\sync\mediasync.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\apiclient\sync\multiserversync.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\apiclient\sync\offlineusersync.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\apiclient\sync\serversync.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\bower_components\fastclick\lib\fastclick.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -96,6 +119,9 @@
<Content Include="dashboard-ui\bower_components\hammerjs\hammer.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\bower_components\howler.js\howler.min.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\bower_components\jquery\dist\jquery.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -105,6 +131,9 @@
<Content Include="dashboard-ui\bower_components\requirejs\require.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\bower_components\Sortable\Sortable.min.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\bower_components\swipebox\src\css\swipebox.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -144,18 +173,103 @@
<Content Include="dashboard-ui\bower_components\webcomponentsjs\webcomponents.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\collectioneditor\collectioneditor.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\directorybrowser\directorybrowser.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\itemidentifier\itemidentifier.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\itemidentifier\itemidentifier.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\imagedownloader\imagedownloader.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\imagedownloader\imagedownloader.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\imageuploader\imageuploader.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\imageuploader\imageuploader.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\medialibrarycreator\medialibrarycreator.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\medialibrarycreator\medialibrarycreator.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\medialibraryeditor\medialibraryeditor.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\medialibraryeditor\medialibraryeditor.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\metadataeditor\metadataeditor.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\metadataeditor\metadataeditor.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\paperdialoghelper.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\playlisteditor\playlisteditor.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\components\prompt.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\cordova\android\localsync.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\cordova\android\logging.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\cordova\android\newapp.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\cordova\fileupload.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\cordova\ios\backgroundfetch.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\cordova\ios\tabbar.js" />
+ <Content Include="dashboard-ui\cordova\ios\vlcplayer.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\cordova\localassetmanager.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\cordova\prompt.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\cordova\searchmenu.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\cordova\sharingwidget.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\devices\ie\ie.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\css\images\ani_equalizer_black.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\css\images\ani_equalizer_white.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -192,6 +306,15 @@
<Content Include="dashboard-ui\css\nowplayingbar.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\components\imageeditor\imageeditor.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\devices\ie\ie.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\favorites.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\livetvguideprovider.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -213,9 +336,6 @@
<Content Include="dashboard-ui\scripts\actionsheet.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\collectioneditor.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\globalize.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -249,6 +369,9 @@
<Content Include="dashboard-ui\scripts\searchmenu.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\searchpage.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\secondaryitems.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -264,22 +387,40 @@
<Content Include="dashboard-ui\scripts\slideshow.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\supporterkeypage.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\wizardlivetvguide.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardlivetvtuner.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\search.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\secondaryitems.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\shared.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\themes\android.css">
+ <Content Include="dashboard-ui\components\subtitleeditor\subtitleeditor.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\devices\android\android.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\themes\halloween\bg.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\themes\ios.css">
+ <Content Include="dashboard-ui\themes\halloween\style.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\themes\halloween\theme.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\devices\ios\ios.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\materialize.css">
@@ -300,9 +441,6 @@
<Content Include="dashboard-ui\cordova\android\appstorage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\cordova\android\localassetmanager.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\cordova\android\mediasession.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -330,6 +468,33 @@
<Content Include="dashboard-ui\thirdparty\emby-icons.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.checkbox.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.collapsible.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.collapsible.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.controlgroup.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.controlgroup.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.popup.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -342,33 +507,24 @@
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.slider.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.icons.css">
+ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.checkbox.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.js">
+ <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.min.js">
+ <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.structure.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.structure.min.css">
- <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\jquerymobile-1.4.5\jquery.mobile.custom.theme.min.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\thirdparty\paper-button-style.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\paper-ie10.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>
@@ -380,6 +536,9 @@
<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\thirdparty\viblast\viblast-video-js.swf">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\thirdparty\viblast\viblast.crypto.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -392,10 +551,13 @@
<Content Include="dashboard-ui\thirdparty\viblast\worker.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\tvproviders\schedulesdirect.js">
+ <Content Include="dashboard-ui\components\tvproviders\schedulesdirect.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\tvproviders\schedulesdirect.template.html">
+ <Content Include="dashboard-ui\components\tvproviders\schedulesdirect.template.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\voice\textprocessor-en-us.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\voice\voice.css">
@@ -506,9 +668,6 @@
<Content Include="dashboard-ui\apiclient\ajax.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\apiclient\alt\ajax.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\apiclient\alt\bean.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -521,9 +680,6 @@
<Content Include="dashboard-ui\cordova\android\androidcredentials.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\cordova\android\filesystem.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\cordova\android\iap.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -537,9 +693,6 @@
<Content Include="dashboard-ui\cordova\externalplayer.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\cordova\filesystem.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\cordova\generaldevice.js" />
<Content Include="dashboard-ui\cordova\iap.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -607,9 +760,6 @@
<Content Include="dashboard-ui\css\images\items\detail\tv.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\items\list\remotesearch.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\media\pause.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -784,9 +934,6 @@
<Content Include="dashboard-ui\metadatasubtitles.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\musicalbumartists.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\collections.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -880,9 +1027,6 @@
<Content Include="dashboard-ui\edititemmetadata.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\episodes.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\gamegenres.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -958,10 +1102,7 @@
<Content Include="dashboard-ui\scripts\dlnasettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\editcollectionitems.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\scripts\edititemsubtitles.js">
+ <Content Include="dashboard-ui\components\subtitleeditor\subtitleeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\encodingsettings.js">
@@ -1087,9 +1228,6 @@
<Content Include="dashboard-ui\scripts\livetvsuggested.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\serversecurity.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\sync.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1111,9 +1249,6 @@
<Content Include="dashboard-ui\scripts\wizardsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\serversecurity.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\apiclient\connectionmanager.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1135,9 +1270,6 @@
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\filesystem.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1756,9 +1888,6 @@
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\icons-svg\video-white.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\livetv.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1780,9 +1909,6 @@
<Content Include="dashboard-ui\thirdparty\jstree\themes\default\throbber.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\tvupcoming.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\userlibraryaccess.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1840,28 +1966,13 @@
<Content Include="dashboard-ui\movies.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\musicalbums.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\musicartists.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\musicgenres.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\musicrecommended.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\musicvideos.html">
+ <Content Include="dashboard-ui\music.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\alphapicker.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\directorybrowser.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\scripts\edititemimages.js">
+ <Content Include="dashboard-ui\components\imageeditor\imageeditor.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\edititemmetadata.js">
@@ -1873,9 +1984,6 @@
<Content Include="dashboard-ui\scripts\musicrecommended.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\musicvideos.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\notifications.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1888,9 +1996,6 @@
<Content Include="dashboard-ui\scripts\tvlatest.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\songs.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\moviecollections.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1915,9 +2020,6 @@
<Content Include="dashboard-ui\scripts\moviegenres.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\moviepeople.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\moviestudios.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1968,9 +2070,6 @@
<Content Include="dashboard-ui\scripts\tvgenres.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\tvpeople.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\tvrecommended.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1980,22 +2079,7 @@
<Content Include="dashboard-ui\scripts\tvstudios.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\tvgenres.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvlatest.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvpeople.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvrecommended.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvshows.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvstudios.html">
+ <Content Include="dashboard-ui\tv.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\userprofiles.html">
@@ -2248,16 +2332,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\scripts\supporterpage.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
- <Content Include="dashboard-ui\supporter.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\css\images\supporter\supporterbadge.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2273,11 +2347,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Content Include="dashboard-ui\scripts\supporterkeypage.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- </ItemGroup>
- <ItemGroup>
<Content Include="dashboard-ui\css\images\notifications\done.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2652,6 +2721,12 @@
<Content Include="dashboard-ui\strings\javascript\zh-TW.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <None Include="dashboard-ui\strings\html\zh-HK.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="dashboard-ui\strings\javascript\zh-HK.json">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
<None Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css.map">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 48f68789b..906f1f4e6 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.249" targetFramework="net45" />
- <package id="WebMarkupMin.Core" version="0.9.12" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
+ <package id="WebMarkupMin.Core" version="1.0.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
index ac4bd8310..353fe31ca 100644
--- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
+++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj
@@ -11,6 +11,7 @@
<AssemblyName>MediaBrowser.XbmcMetadata</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -30,6 +31,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll</HintPath>
+ </Reference>
+ <Reference Include="Patterns.Logging">
+ <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -81,6 +89,9 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index ac39d9d98..c5184ec3d 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -394,11 +394,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var val = reader.ReadElementContentAsString();
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
- {
- hasLanguage.PreferredMetadataLanguage = val;
- }
+ item.PreferredMetadataLanguage = val;
break;
}
@@ -407,11 +403,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var val = reader.ReadElementContentAsString();
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
- {
- hasLanguage.PreferredMetadataCountryCode = val;
- }
+ item.PreferredMetadataCountryCode = val;
break;
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
index f6b78f342..d9c85b92e 100644
--- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Parsers;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -26,7 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
new BaseNfoParser<MusicAlbum>(_logger, _config).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "album.nfo"));
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
index 64cbfe486..fe4906636 100644
--- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Parsers;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -26,7 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
new BaseNfoParser<MusicArtist>(_logger, _config).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "artist.nfo"));
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
index d7815dfb7..abac7f544 100644
--- a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
@@ -6,6 +6,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -55,7 +56,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
FileSystem = fileSystem;
}
- protected abstract FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService);
+ protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
index fa9ef7797..605a09709 100644
--- a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
@@ -8,6 +8,7 @@ using MediaBrowser.XbmcMetadata.Savers;
using System.IO;
using System.Linq;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -41,7 +42,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
}
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return MovieNfoSaver.GetMovieSavePaths(info, FileSystem)
.Select(directoryService.GetFile)
diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
index b7bfdeeb0..470a40f09 100644
--- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
@@ -8,6 +8,7 @@ using MediaBrowser.XbmcMetadata.Parsers;
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -32,7 +33,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
result.Images = images;
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
var path = Path.ChangeExtension(info.Path, ".nfo");
diff --git a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
index 6c9949fc2..62a8c6047 100644
--- a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using CommonIO;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
index ec543ee0c..777f2f847 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Parsers;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -26,7 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
new SeasonNfoParser(_logger, _config).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "season.nfo"));
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
index d9128821c..50649fbc0 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Parsers;
using System.IO;
using System.Threading;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Providers
{
@@ -26,7 +27,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
new SeriesNfoParser(_logger, _config).Fetch(result, path, cancellationToken);
}
- protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+ protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{
return directoryService.GetFile(Path.Combine(info.Path, "tvshow.nfo"));
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
index 9bd9ac65e..660322c61 100644
--- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
@@ -10,6 +10,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
index b8ea74588..c9fad8a7c 100644
--- a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
@@ -10,6 +10,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index b6f497a76..fa58b67da 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -19,6 +19,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
+using CommonIO;
using MediaBrowser.Model.Extensions;
namespace MediaBrowser.XbmcMetadata.Savers
@@ -199,6 +200,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void SaveToFile(Stream stream, string path)
{
+ FileSystem.CreateDirectory(Path.GetDirectoryName(path));
+
var file = new FileInfo(path);
var wasHidden = false;
@@ -597,17 +600,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("tvcomid", tvcom);
}
- var hasLanguage = item as IHasPreferredMetadataLanguage;
- if (hasLanguage != null)
+ if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage))
{
- if (!string.IsNullOrEmpty(hasLanguage.PreferredMetadataLanguage))
- {
- writer.WriteElementString("language", hasLanguage.PreferredMetadataLanguage);
- }
- if (!string.IsNullOrEmpty(hasLanguage.PreferredMetadataCountryCode))
- {
- writer.WriteElementString("countrycode", hasLanguage.PreferredMetadataCountryCode);
- }
+ writer.WriteElementString("language", item.PreferredMetadataLanguage);
+ }
+ if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode))
+ {
+ writer.WriteElementString("countrycode", item.PreferredMetadataCountryCode);
}
if (item.PremiereDate.HasValue && !(item is Episode))
@@ -817,7 +816,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (options.SaveImagePathsInNfo)
{
- AddImages(item, writer, fileSystem, config);
+ AddImages(item, writer, libraryManager, config);
}
AddUserData(item, writer, userManager, userDataRepo, options);
@@ -881,20 +880,23 @@ namespace MediaBrowser.XbmcMetadata.Savers
StringComparison.OrdinalIgnoreCase);
}
- private static void AddImages(BaseItem item, XmlWriter writer, IFileSystem fileSystem, IServerConfigurationManager config)
+ private static void AddImages(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IServerConfigurationManager config)
{
writer.WriteStartElement("art");
- var poster = item.PrimaryImagePath;
+ var image = item.GetImageInfo(ImageType.Primary, 0);
- if (!string.IsNullOrEmpty(poster))
+ if (image != null && image.IsLocalFile)
{
- writer.WriteElementString("poster", GetPathToSave(item.PrimaryImagePath, fileSystem, config));
+ writer.WriteElementString("poster", GetPathToSave(image.Path, libraryManager, config));
}
foreach (var backdrop in item.GetImages(ImageType.Backdrop))
{
- writer.WriteElementString("fanart", GetPathToSave(backdrop.Path, fileSystem, config));
+ if (backdrop.IsLocalFile)
+ {
+ writer.WriteElementString("fanart", GetPathToSave(backdrop.Path, libraryManager, config));
+ }
}
writer.WriteEndElement();
@@ -983,10 +985,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
try
{
var personEntity = libraryManager.GetPerson(person.Name);
+ var image = personEntity.GetImageInfo(ImageType.Primary, 0);
- if (!string.IsNullOrEmpty(personEntity.PrimaryImagePath))
+ if (image != null && image.IsLocalFile)
{
- writer.WriteElementString("thumb", GetPathToSave(personEntity.PrimaryImagePath, fileSystem, config));
+ writer.WriteElementString("thumb", GetPathToSave(image.Path, libraryManager, config));
}
}
catch (Exception)
@@ -998,11 +1001,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
}
}
- private static string GetPathToSave(string path, IFileSystem fileSystem, IServerConfigurationManager config)
+ private static string GetPathToSave(string path, ILibraryManager libraryManager, IServerConfigurationManager config)
{
foreach (var map in config.Configuration.PathSubstitutions)
{
- path = fileSystem.SubstitutePath(path, map.From, map.To);
+ path = libraryManager.SubstitutePath(path, map.From, map.To);
}
return path;
diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs
index 6fd396e40..b08521794 100644
--- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index ddbd528d9..3734f3f36 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
@@ -29,7 +30,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
var list = new List<string>();
- if (item.VideoType == VideoType.Dvd)
+ if (item.VideoType == VideoType.Dvd && !item.IsPlaceHolder)
{
var path = item.ContainingFolderPath;
diff --git a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs
index 49ace7702..edb468d64 100644
--- a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs
@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
@@ -39,7 +40,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
return false;
}
- return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && File.Exists(GetSavePath(item)));
+ return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && FileSystem.FileExists(GetSavePath(item)));
}
protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer)
diff --git a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
index 099e8dbd7..11df3ae6f 100644
--- a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
+using CommonIO;
namespace MediaBrowser.XbmcMetadata.Savers
{
diff --git a/MediaBrowser.XbmcMetadata/packages.config b/MediaBrowser.XbmcMetadata/packages.config
new file mode 100644
index 000000000..fad6af08e
--- /dev/null
+++ b/MediaBrowser.XbmcMetadata/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="CommonIO" version="1.0.0.5" targetFramework="net45" />
+ <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index f92e05492..8fa5b665d 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.633</version>
+ <version>3.0.638</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.633" />
+ <dependency id="MediaBrowser.Common" version="3.0.638" />
<dependency id="NLog" version="3.2.1" />
- <dependency id="SimpleInjector" version="2.8.0" />
+ <dependency id="SimpleInjector" version="3.0.5" />
</dependencies>
</metadata>
<files>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 04d4deb7c..cec3f63d5 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.633</version>
+ <version>3.0.638</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 2a75ac3a8..6f778882a 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.633</version>
+ <version>3.0.638</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 da8309410..b6edd8719 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.633</version>
+ <version>3.0.638</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.633" />
+ <dependency id="MediaBrowser.Common" version="3.0.638" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>
diff --git a/OpenSubtitlesHandler/MovieHasher.cs b/OpenSubtitlesHandler/MovieHasher.cs
index a14bd20f8..8d11d8267 100644
--- a/OpenSubtitlesHandler/MovieHasher.cs
+++ b/OpenSubtitlesHandler/MovieHasher.cs
@@ -9,17 +9,7 @@ namespace OpenSubtitlesHandler
{
public class MovieHasher
{
- public static byte[] ComputeMovieHash(string filename)
- {
- byte[] result;
- using (Stream input = File.OpenRead(filename))
- {
- result = ComputeMovieHash(input);
- }
- return result;
- }
-
- private static byte[] ComputeMovieHash(Stream input)
+ public static byte[] ComputeMovieHash(Stream input)
{
long lhash, streamsize;
streamsize = input.Length;
diff --git a/OpenSubtitlesHandler/Utilities.cs b/OpenSubtitlesHandler/Utilities.cs
index 7f0f93009..4340d4c3f 100644
--- a/OpenSubtitlesHandler/Utilities.cs
+++ b/OpenSubtitlesHandler/Utilities.cs
@@ -44,7 +44,7 @@ namespace OpenSubtitlesHandler
/// <returns>The hash as Hexadecimal string</returns>
public static string ComputeHash(string fileName)
{
- byte[] hash = MovieHasher.ComputeMovieHash(fileName);
+ byte[] hash = MovieHasher.ComputeMovieHash(File.OpenRead(fileName));
return MovieHasher.ToHexadecimal(hash);
}
/// <summary>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 30ce35ee1..4b8a8c61d 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
//[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5724.6")]
+[assembly: AssemblyVersion("3.0.5768.7")]