From 08fb2707be127b7940ab3ea095011e2180b6dabf Mon Sep 17 00:00:00 2001 From: Jose Alacan Date: Wed, 24 Aug 2016 20:08:03 -0400 Subject: Only usermanager should have access to the userrepository --- MediaBrowser.Server.Implementations/Session/SessionManager.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index b21fcddd4..9243a951e 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -43,11 +43,6 @@ namespace MediaBrowser.Server.Implementations.Session /// private readonly IUserDataManager _userDataRepository; - /// - /// The _user repository - /// - private readonly IUserRepository _userRepository; - /// /// The _logger /// @@ -99,11 +94,10 @@ namespace MediaBrowser.Server.Implementations.Session private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1); - public SessionManager(IUserDataManager userDataRepository, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager) + public SessionManager(IUserDataManager userDataRepository, ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager) { _userDataRepository = userDataRepository; _logger = logger; - _userRepository = userRepository; _libraryManager = libraryManager; _userManager = userManager; _musicManager = musicManager; @@ -253,8 +247,7 @@ namespace MediaBrowser.Server.Implementations.Session { try { - // Save this directly. No need to fire off all the events for this. - await _userRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); + await _userManager.UpdateUser(user).ConfigureAwait(false); } catch (Exception ex) { -- cgit v1.2.3 From 038cfabca5e057da73df4719a7c0ad5e37400eb5 Mon Sep 17 00:00:00 2001 From: Jose Alacan Date: Wed, 24 Aug 2016 20:12:15 -0400 Subject: Session manager works with the userdata manager not the repository --- .../Session/SessionManager.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 9243a951e..9f52f799b 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Session /// /// The _user data repository /// - private readonly IUserDataManager _userDataRepository; + private readonly IUserDataManager _userDataManager; /// /// The _logger @@ -94,9 +94,9 @@ namespace MediaBrowser.Server.Implementations.Session private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1); - public SessionManager(IUserDataManager userDataRepository, ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager) + public SessionManager(IUserDataManager userDataManager, ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager) { - _userDataRepository = userDataRepository; + _userDataManager = userDataManager; _logger = logger; _libraryManager = libraryManager; _userManager = userManager; @@ -631,7 +631,7 @@ namespace MediaBrowser.Server.Implementations.Session /// Task. private async Task OnPlaybackStart(Guid userId, IHasUserData item) { - var data = _userDataRepository.GetUserData(userId, item); + var data = _userDataManager.GetUserData(userId, item); data.PlayCount++; data.LastPlayedDate = DateTime.UtcNow; @@ -641,7 +641,7 @@ namespace MediaBrowser.Server.Implementations.Session data.Played = true; } - await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); + await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); } /// @@ -708,17 +708,17 @@ namespace MediaBrowser.Server.Implementations.Session private async Task OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info) { - var data = _userDataRepository.GetUserData(user.Id, item); + var data = _userDataManager.GetUserData(user.Id, item); var positionTicks = info.PositionTicks; if (positionTicks.HasValue) { - _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); + _userDataManager.UpdatePlayState(item, data, positionTicks.Value); UpdatePlaybackSettings(user, info, data); - await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); + await _userDataManager.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); } } @@ -844,11 +844,11 @@ namespace MediaBrowser.Server.Implementations.Session if (!playbackFailed) { - var data = _userDataRepository.GetUserData(userId, item); + var data = _userDataManager.GetUserData(userId, item); if (positionTicks.HasValue) { - playedToCompletion = _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); + playedToCompletion = _userDataManager.UpdatePlayState(item, data, positionTicks.Value); } else { @@ -859,7 +859,7 @@ namespace MediaBrowser.Server.Implementations.Session playedToCompletion = true; } - await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false); + await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false); } return playedToCompletion; -- cgit v1.2.3 From d95c0e8324284b7391fb1d6a275c8af18508141b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 14 Sep 2016 17:34:19 -0400 Subject: fix web socket session creation --- MediaBrowser.Api/ConnectService.cs | 34 ++++++++++++++++++---- .../Session/AuthenticationRequest.cs | 1 + MediaBrowser.Providers/Manager/MetadataService.cs | 2 -- .../Library/LibraryManager.cs | 12 ++++---- .../Session/SessionManager.cs | 15 ++++++++-- 5 files changed, 49 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs index 4bcd33d9e..494a6e756 100644 --- a/MediaBrowser.Api/ConnectService.cs +++ b/MediaBrowser.Api/ConnectService.cs @@ -7,6 +7,7 @@ using ServiceStack; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Controller.Session; namespace MediaBrowser.Api { @@ -76,12 +77,12 @@ namespace MediaBrowser.Api public class ConnectService : BaseApiService { private readonly IConnectManager _connectManager; - private readonly IUserManager _userManager; + private readonly ISessionManager _sessionManager; - public ConnectService(IConnectManager connectManager, IUserManager userManager) + public ConnectService(IConnectManager connectManager, ISessionManager sessionManager) { _connectManager = connectManager; - _userManager = userManager; + _sessionManager = sessionManager; } public object Post(CreateConnectLink request) @@ -141,10 +142,33 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(); } + var auth = AuthorizationContext.GetAuthorizationInfo(Request); + + if (string.IsNullOrWhiteSpace(auth.Client)) + { + return ToOptimizedResult(new ConnectAuthenticationExchangeResult + { + AccessToken = user.ConnectAccessKey, + LocalUserId = user.Id.ToString("N") + }); + } + + var session = await _sessionManager.CreateNewSession(new AuthenticationRequest + { + App = auth.Client, + AppVersion = auth.Version, + DeviceId = auth.DeviceId, + DeviceName = auth.Device, + RemoteEndPoint = Request.RemoteIp, + Username = user.Name, + UserId = user.Id.ToString("N") + + }).ConfigureAwait(false); + return ToOptimizedResult(new ConnectAuthenticationExchangeResult { - AccessToken = user.ConnectAccessKey, - LocalUserId = user.Id.ToString("N") + AccessToken = session.AccessToken, + LocalUserId = session.User.Id }); } } diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs index bfd7f928b..362f5b2b9 100644 --- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs +++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs @@ -4,6 +4,7 @@ namespace MediaBrowser.Controller.Session public class AuthenticationRequest { public string Username { get; set; } + public string UserId { get; set; } public string PasswordSha1 { get; set; } public string PasswordMd5 { get; set; } public string App { get; set; } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 85e25d2b6..e16e76bfc 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -547,8 +547,6 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - refreshResult.Failures++; - Logger.ErrorException("Error in {0}", ex, provider.Name); // If a local provider fails, consider that a failure diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index bd408c9d3..1f8c77953 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -695,7 +695,7 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, - Folder parent, + Folder parent, LibraryOptions libraryOptions, string collectionType, IItemResolver[] resolvers) @@ -1490,10 +1490,10 @@ namespace MediaBrowser.Server.Implementations.Library private void AddUserToQuery(InternalItemsQuery query, User user) { - if (query.AncestorIds.Length == 0 && - !query.ParentId.HasValue && - query.ChannelIds.Length == 0 && - query.TopParentIds.Length == 0 && + if (query.AncestorIds.Length == 0 && + !query.ParentId.HasValue && + query.ChannelIds.Length == 0 && + query.TopParentIds.Length == 0 && string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey) && query.ItemIds.Length == 0) { @@ -2552,7 +2552,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("to"); } - var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase); + var newPath = path.Replace(from.Trim(), to.Trim(), StringComparison.OrdinalIgnoreCase); if (!string.Equals(newPath, path)) { diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index b21fcddd4..afcdf9d90 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1341,8 +1341,19 @@ namespace MediaBrowser.Server.Implementations.Session private async Task AuthenticateNewSessionInternal(AuthenticationRequest request, bool enforcePassword) { - var user = _userManager.Users - .FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase)); + User user = null; + if (!string.IsNullOrWhiteSpace(request.UserId)) + { + var idGuid = new Guid(request.UserId); + user = _userManager.Users + .FirstOrDefault(i => i.Id == idGuid); + } + + if (user == null) + { + user = _userManager.Users + .FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase)); + } if (user != null && !string.IsNullOrWhiteSpace(request.DeviceId)) { -- cgit v1.2.3 From 05edb9f4bdcdf7733bcd7e6e74a876bbc2b5c064 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 18 Sep 2016 16:38:38 -0400 Subject: update timeshifting --- MediaBrowser.Api/ApiEntryPoint.cs | 13 ++++++++++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 26 ++++++++++++++++------ MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 15 +++---------- MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs | 4 +--- MediaBrowser.Api/Playback/StreamState.cs | 4 ++++ MediaBrowser.Api/Subtitles/SubtitleService.cs | 2 +- .../Library/IMediaSourceManager.cs | 5 +---- MediaBrowser.Dlna/PlayTo/PlayToController.cs | 7 +++++- .../Library/MediaSourceManager.cs | 22 +++++++++++++++++- .../LiveTv/EmbyTV/EmbyTV.cs | 6 ++--- .../LiveTv/TunerHosts/BaseTunerHost.cs | 3 +-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 17 ++++++++------ .../Session/SessionManager.cs | 8 +++---- 13 files changed, 86 insertions(+), 46 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 7c5f7cde4..214fb7488 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Api { @@ -187,7 +188,8 @@ namespace MediaBrowser.Api CancellationTokenSource = cancellationTokenSource, Id = transcodingJobId, PlaySessionId = playSessionId, - LiveStreamId = liveStreamId + LiveStreamId = liveStreamId, + MediaSource = state.MediaSource }; _activeTranscodingJobs.Add(job); @@ -281,6 +283,14 @@ namespace MediaBrowser.Api } } + public TranscodingJob GetTranscodingJob(string playSessionId) + { + lock (_activeTranscodingJobs) + { + return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase)); + } + } + /// /// Called when [transcode begin request]. /// @@ -656,6 +666,7 @@ namespace MediaBrowser.Api /// Gets or sets the path. /// /// The path. + public MediaSourceInfo MediaSource { get; set; } public string Path { get; set; } /// /// Gets or sets the type. diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 4a62da6f6..eee6bfb65 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1847,18 +1847,30 @@ namespace MediaBrowser.Api.Playback var archivable = item as IArchivable; state.IsInputArchive = archivable != null && archivable.IsArchive; - MediaSourceInfo mediaSource; + MediaSourceInfo mediaSource = null; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { - var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); + //TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? + // ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) + // : null; - mediaSource = string.IsNullOrEmpty(request.MediaSourceId) - ? mediaSources.First() - : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId)); + //if (currentJob != null) + //{ + // mediaSource = currentJob.MediaSource; + //} - if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase)) + if (mediaSource == null) { - mediaSource = mediaSources.First(); + var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); + + mediaSource = string.IsNullOrEmpty(request.MediaSourceId) + ? mediaSources.First() + : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId)); + + if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase)) + { + mediaSource = mediaSources.First(); + } } } else diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index a0ac96b9d..1e056f670 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Api.Playback.Hls throw; } - var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; + var waitForSegments = state.SegmentLength >= 10 ? 2 : (state.SegmentLength > 3 || !isLive ? 3 : 4); await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); } } @@ -128,10 +128,9 @@ namespace MediaBrowser.Api.Playback.Hls var audioBitrate = state.OutputAudioBitrate ?? 0; var videoBitrate = state.OutputVideoBitrate ?? 0; - var appendBaselineStream = false; var baselineStreamBitrate = 64000; - var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, appendBaselineStream, baselineStreamBitrate); + var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, baselineStreamBitrate); job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType); @@ -161,7 +160,7 @@ namespace MediaBrowser.Api.Playback.Hls } } - private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate) + private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, int baselineStreamBitrate) { var builder = new StringBuilder(); @@ -175,14 +174,6 @@ namespace MediaBrowser.Api.Playback.Hls var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8"); builder.AppendLine(playlistUrl); - // Low bitrate stream - if (includeBaselineStream) - { - builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + baselineStreamBitrate.ToString(UsCulture)); - playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "-low/stream.m3u8"); - builder.AppendLine(playlistUrl); - } - return builder.ToString(); } diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 27deaf25e..976fed3f0 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -68,8 +68,6 @@ namespace MediaBrowser.Api.Playback.Hls [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] public class GetHlsVideoSegmentLegacy : VideoStreamRequest { - // TODO: Deprecate with new iOS app - public string PlaylistId { get; set; } /// @@ -113,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Hls var file = request.SegmentId + Path.GetExtension(Request.PathInfo); file = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, file); - var normalizedPlaylistId = request.PlaylistId.Replace("-low", string.Empty); + var normalizedPlaylistId = request.PlaylistId; var playlistPath = Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*") .FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1); diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 2e92c4a49..d6ccdd1fd 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -88,6 +88,10 @@ namespace MediaBrowser.Api.Playback return 10; } + if (!RunTimeTicks.HasValue) + { + return 10; + } return 6; } diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index fe13e8b21..b07a31a87 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Subtitles { var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); - var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, false).ConfigureAwait(false); + var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false); var builder = new StringBuilder(); diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index a77d88049..1df77cdc9 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -60,11 +60,8 @@ namespace MediaBrowser.Controller.Library /// /// Gets the static media source. /// - /// The item. - /// The media source identifier. - /// if set to true [enable path substitution]. /// MediaSourceInfo. - Task GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution); + Task GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken); /// /// Opens the media source. diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index d958d0e37..6345e2105 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -827,6 +827,7 @@ namespace MediaBrowser.Dlna.PlayTo public string DeviceId { get; set; } public string MediaSourceId { get; set; } + public string LiveStreamId { get; set; } public BaseItem Item { get; set; } public MediaSourceInfo MediaSource { get; set; } @@ -910,6 +911,10 @@ namespace MediaBrowser.Dlna.PlayTo { request.StartPositionTicks = long.Parse(val, CultureInfo.InvariantCulture); } + else if (i == 22) + { + request.LiveStreamId = val; + } } request.Item = string.IsNullOrWhiteSpace(request.ItemId) @@ -920,7 +925,7 @@ namespace MediaBrowser.Dlna.PlayTo request.MediaSource = hasMediaSources == null ? null - : (await mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).ConfigureAwait(false)); + : (await mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, request.LiveStreamId, false, CancellationToken.None).ConfigureAwait(false)); return request; } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 4a533ff93..c20245a6e 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -221,8 +221,28 @@ namespace MediaBrowser.Server.Implementations.Library } } - public async Task GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution) + public async Task GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken) { + if (!string.IsNullOrWhiteSpace(liveStreamId)) + { + return await GetLiveStream(liveStreamId, cancellationToken).ConfigureAwait(false); + } + //await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + //try + //{ + // var stream = _openStreams.Values.FirstOrDefault(i => string.Equals(i.MediaSource.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); + + // if (stream != null) + // { + // return stream.MediaSource; + // } + //} + //finally + //{ + // _liveStreamSemaphore.Release(); + //} + var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index b508110cf..3d7b4abef 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -763,7 +763,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV throw new ApplicationException("Tuner not found."); } - private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) + private async Task> GetChannelStreamInternal(string channelId, CancellationToken cancellationToken) { _logger.Info("Streaming Channel " + channelId); @@ -771,7 +771,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { try { - var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); + var result = await hostInstance.GetChannelStream(channelId, null, cancellationToken).ConfigureAwait(false); return new Tuple(result.Item1, hostInstance, result.Item2); } @@ -994,7 +994,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV try { - var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None).ConfigureAwait(false); + var result = await GetChannelStreamInternal(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); isResourceOpen = true; semaphore = result.Item3; var mediaStreamInfo = result.Item1; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 7aa9eb1cf..3f6bb140b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -223,8 +223,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts } } - var stream = - await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); + var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); if (EnableMediaProbing) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index fd4775938..c5bd648cf 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -319,18 +319,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun videoBitrate = 1000000; } - if (string.IsNullOrWhiteSpace(videoCodec)) + var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false); + var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase)); + if (channel != null) { - var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false); - var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase)); - if (channel != null) + if (string.IsNullOrWhiteSpace(videoCodec)) { videoCodec = channel.VideoCodec; - audioCodec = channel.AudioCodec; + } + audioCodec = channel.AudioCodec; + if (!videoBitrate.HasValue) + { videoBitrate = (channel.IsHD ?? true) ? 15000000 : 2000000; - audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000; } + audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000; } // normalize @@ -380,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun BitRate = audioBitrate } }, - RequiresOpening = false, + RequiresOpening = true, RequiresClosing = false, BufferMs = 0, Container = "ts", diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index afcdf9d90..f56af5b61 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -307,9 +307,9 @@ namespace MediaBrowser.Server.Implementations.Session } } - private Task GetMediaSource(IHasMediaSources item, string mediaSourceId) + private Task GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId) { - return _mediaSourceManager.GetMediaSource(item, mediaSourceId, false); + return _mediaSourceManager.GetMediaSource(item, mediaSourceId, liveStreamId, false, CancellationToken.None); } /// @@ -337,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session var hasMediaSources = libraryItem as IHasMediaSources; if (hasMediaSources != null) { - mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId).ConfigureAwait(false); + mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false); if (mediaSource != null) { @@ -792,7 +792,7 @@ namespace MediaBrowser.Server.Implementations.Session var hasMediaSources = libraryItem as IHasMediaSources; if (hasMediaSources != null) { - mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId).ConfigureAwait(false); + mediaSource = await GetMediaSource(hasMediaSources, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false); } info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource); -- cgit v1.2.3 From 48d7f686eb2212a19ee988c18c39d9fe1027d483 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 24 Sep 2016 13:58:17 -0400 Subject: update network share settings --- MediaBrowser.Api/StartupWizardService.cs | 6 --- .../MediaBrowser.Controller.csproj | 1 - .../RelatedMedia/IRelatedMediaProvider.cs | 11 ------ MediaBrowser.Dlna/PlayTo/Device.cs | 2 +- .../Library/LibraryManager.cs | 44 ++++++++++++++++++++++ .../LiveTv/LiveTvManager.cs | 14 ------- .../Session/SessionManager.cs | 6 +-- MediaBrowser.Server.Mono/app.config | 2 +- .../ApplicationPathHelper.cs | 8 +++- 9 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 MediaBrowser.Controller/RelatedMedia/IRelatedMediaProvider.cs (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index ef898eb53..176b497d7 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -148,12 +148,6 @@ namespace MediaBrowser.Api { var user = _userManager.Users.First(); - // TODO: This should be handled internally by xbmc metadata - const string metadataKey = "xbmcmetadata"; - var metadata = _config.GetConfiguration(metadataKey); - metadata.UserId = user.Id.ToString("N"); - _config.SaveConfiguration(metadataKey, metadata); - user.Name = request.Name; await _userManager.UpdateUser(user).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 8fae46906..cb36afa5f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -318,7 +318,6 @@ - diff --git a/MediaBrowser.Controller/RelatedMedia/IRelatedMediaProvider.cs b/MediaBrowser.Controller/RelatedMedia/IRelatedMediaProvider.cs deleted file mode 100644 index bb2a0cd89..000000000 --- a/MediaBrowser.Controller/RelatedMedia/IRelatedMediaProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MediaBrowser.Controller.RelatedMedia -{ - public interface IRelatedMediaProvider - { - /// - /// Gets the name. - /// - /// The name. - string Name { get; } - } -} diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index d1802b3ad..b656bc66e 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -474,7 +474,7 @@ namespace MediaBrowser.Dlna.PlayTo if (_disposed) return; - _logger.ErrorException("Error updating device info for {0}", ex, Properties.Name); + //_logger.ErrorException("Error updating device info for {0}", ex, Properties.Name); _successiveStopCount++; _connectFailureCount++; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index f62847bcc..7c3196065 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -2829,6 +2829,16 @@ namespace MediaBrowser.Server.Implementations.Library throw new DirectoryNotFoundException("The path does not exist."); } + if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !_fileSystem.DirectoryExists(pathInfo.NetworkPath)) + { + throw new DirectoryNotFoundException("The network path does not exist."); + } + + if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !_fileSystem.DirectoryExists(pathInfo.NetworkPath)) + { + throw new DirectoryNotFoundException("The network path does not exist."); + } + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); @@ -2850,6 +2860,8 @@ namespace MediaBrowser.Server.Implementations.Library { var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath); + SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); + var list = libraryOptions.PathInfos.ToList(); list.Add(pathInfo); libraryOptions.PathInfos = list.ToArray(); @@ -2865,11 +2877,18 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("path"); } + if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !_fileSystem.DirectoryExists(pathInfo.NetworkPath)) + { + throw new DirectoryNotFoundException("The network path does not exist."); + } + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath); + SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); + var list = libraryOptions.PathInfos.ToList(); foreach (var originalPathInfo in list) { @@ -2879,11 +2898,36 @@ namespace MediaBrowser.Server.Implementations.Library break; } } + libraryOptions.PathInfos = list.ToArray(); CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions); } + private void SyncLibraryOptionsToLocations(string virtualFolderPath, LibraryOptions options) + { + var topLibraryFolders = GetUserRootFolder().Children.ToList(); + var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders); + + if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length) + { + var list = options.PathInfos.ToList(); + + foreach (var location in info.Locations) + { + if (!list.Any(i => string.Equals(i.Path, location, StringComparison.Ordinal))) + { + list.Add(new MediaPathInfo + { + Path = location + }); + } + } + + options.PathInfos = list.ToArray(); + } + } + public void RemoveVirtualFolder(string name, bool refreshLibrary) { if (string.IsNullOrWhiteSpace(name)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 9b340a9f9..8a4572813 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2855,20 +2855,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase)) - { - var config = GetConfiguration(); - if (config.TunerHosts.Count(i => i.IsEnabled) > 0 && - config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0) - { - return Task.FromResult(new MBRegistrationRecord - { - IsRegistered = true, - IsValid = true - }); - } - } - return _security.GetRegistrationStatus(feature); } diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index f56af5b61..48f48cdcc 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -294,11 +294,9 @@ namespace MediaBrowser.Server.Implementations.Session var key = GetSessionKey(session.Client, session.DeviceId); SessionInfo removed; + _activeConnections.TryRemove(key, out removed); - if (_activeConnections.TryRemove(key, out removed)) - { - OnSessionEnded(removed); - } + OnSessionEnded(session); } } finally diff --git a/MediaBrowser.Server.Mono/app.config b/MediaBrowser.Server.Mono/app.config index e14b908ad..e8c7a9326 100644 --- a/MediaBrowser.Server.Mono/app.config +++ b/MediaBrowser.Server.Mono/app.config @@ -8,7 +8,7 @@ - + diff --git a/MediaBrowser.Server.Startup.Common/ApplicationPathHelper.cs b/MediaBrowser.Server.Startup.Common/ApplicationPathHelper.cs index 285806791..254a782db 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationPathHelper.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationPathHelper.cs @@ -18,10 +18,16 @@ namespace MediaBrowser.Server.Startup.Common useDebugPath = true; #endif - var programDataPath = useDebugPath ? ConfigurationManager.AppSettings["DebugProgramDataPath"] : ConfigurationManager.AppSettings["ReleaseProgramDataPath"]; + var programDataPath = useDebugPath ? + ConfigurationManager.AppSettings["DebugProgramDataPath"] : + ConfigurationManager.AppSettings["ReleaseProgramDataPath"]; programDataPath = programDataPath.Replace("%ApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); + programDataPath = programDataPath + .Replace('/', Path.DirectorySeparatorChar) + .Replace('\\', Path.DirectorySeparatorChar); + // If it's a relative path, e.g. "..\" if (!Path.IsPathRooted(programDataPath)) { -- cgit v1.2.3 From 76c7bfcb6795771cb06ef354fbf76d6e39de8948 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 29 Sep 2016 08:55:49 -0400 Subject: update closing of streams --- MediaBrowser.Api/ApiEntryPoint.cs | 8 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 46 ++++++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 16 +-- MediaBrowser.Api/Playback/MediaInfoService.cs | 2 +- .../Progressive/BaseProgressiveStreamingService.cs | 2 - MediaBrowser.Api/Playback/StreamState.cs | 2 +- .../Entities/InternalItemsQuery.cs | 2 + .../Library/IMediaSourceManager.cs | 3 +- .../Library/IMediaSourceProvider.cs | 3 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 5 +- MediaBrowser.Controller/LiveTv/LiveStream.cs | 23 +++- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 53 +++++++- MediaBrowser.Controller/LiveTv/TimerInfo.cs | 1 + MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 7 +- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 24 ++++ MediaBrowser.Model/LiveTv/ProgramQuery.cs | 7 + .../LiveTv/RecommendedProgramQuery.cs | 6 + MediaBrowser.Model/LiveTv/RecordingQuery.cs | 1 + .../Channels/ChannelDynamicMediaSourceProvider.cs | 2 +- .../Library/MediaSourceManager.cs | 59 +++++---- .../LiveTv/EmbyTV/DirectRecorder.cs | 16 +-- .../LiveTv/EmbyTV/EmbyTV.cs | 143 +++++++++++++-------- .../LiveTv/EmbyTV/EncodedRecorder.cs | 39 +----- .../LiveTv/EmbyTV/RecordingHelper.cs | 1 + .../LiveTv/LiveTvManager.cs | 90 ++++++++----- .../LiveTv/LiveTvMediaSourceProvider.cs | 4 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 4 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 8 -- .../TunerHosts/HdHomerun/HdHomerunLiveStream.cs | 7 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 5 - .../Persistence/SqliteItemRepository.cs | 113 +++++++++++++--- .../Session/SessionManager.cs | 2 +- .../Sync/SyncedMediaSourceProvider.cs | 2 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 90 +------------ 36 files changed, 475 insertions(+), 326 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 2f5b9e1e0..c6e45c61a 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -567,7 +567,7 @@ namespace MediaBrowser.Api { try { - await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { @@ -789,12 +789,12 @@ namespace MediaBrowser.Api { if (KillTimer == null) { - Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite); } else { - Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer.Change(intervalMs, Timeout.Infinite); } } @@ -813,7 +813,7 @@ namespace MediaBrowser.Api { var intervalMs = PingTimeout; - Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); + //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer.Change(intervalMs, Timeout.Infinite); } } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index a5f8fce6e..9c1105082 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -48,6 +48,21 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? StartIndex { get; set; } + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsMovie { get; set; } + + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } + + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsKids { get; set; } + + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { get; set; } + /// /// The maximum number of items to return /// @@ -163,6 +178,7 @@ namespace MediaBrowser.Api.LiveTv public bool? IsSeries { get; set; } public bool? IsKids { get; set; } public bool? IsSports { get; set; } + public bool? IsNews { get; set; } public GetRecordings() { @@ -309,6 +325,12 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } + + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsKids { get; set; } @@ -380,15 +402,21 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasAired { get; set; } - [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] - public bool? IsSports { get; set; } + [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSeries { get; set; } - [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } - [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsNews { get; set; } + + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsKids { get; set; } + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { get; set; } + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableImages { get; set; } @@ -815,6 +843,11 @@ namespace MediaBrowser.Api.LiveTv IsLiked = request.IsLiked, IsDisliked = request.IsDisliked, EnableFavoriteSorting = request.EnableFavoriteSorting, + IsMovie = request.IsMovie, + IsSeries = request.IsSeries, + IsNews = request.IsNews, + IsKids = request.IsKids, + IsSports = request.IsSports, AddCurrentProgram = request.AddCurrentProgram }, CancellationToken.None).ConfigureAwait(false); @@ -897,7 +930,9 @@ namespace MediaBrowser.Api.LiveTv query.Limit = request.Limit; query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortOrder = request.SortOrder; + query.IsNews = request.IsNews; query.IsMovie = request.IsMovie; + query.IsSeries = request.IsSeries; query.IsKids = request.IsKids; query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); @@ -915,8 +950,10 @@ namespace MediaBrowser.Api.LiveTv IsAiring = request.IsAiring, Limit = request.Limit, HasAired = request.HasAired, + IsSeries = request.IsSeries, IsMovie = request.IsMovie, IsKids = request.IsKids, + IsNews = request.IsNews, IsSports = request.IsSports, EnableTotalRecordCount = request.EnableTotalRecordCount }; @@ -948,6 +985,7 @@ namespace MediaBrowser.Api.LiveTv IsInProgress = request.IsInProgress, EnableTotalRecordCount = request.EnableTotalRecordCount, IsMovie = request.IsMovie, + IsNews = request.IsNews, IsSeries = request.IsSeries, IsKids = request.IsKids, IsSports = request.IsSports diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index fe9869664..8e57650b4 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1861,14 +1861,14 @@ namespace MediaBrowser.Api.Playback MediaSourceInfo mediaSource = null; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { - //TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? - // ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) - // : null; - - //if (currentJob != null) - //{ - // mediaSource = currentJob.MediaSource; - //} + TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? + ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) + : null; + + if (currentJob != null) + { + mediaSource = currentJob.MediaSource; + } if (mediaSource == null) { diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 656b2ee08..761538c83 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback public void Post(CloseMediaSource request) { - var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId, CancellationToken.None); + var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId); Task.WaitAll(task); } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index a68319109..4bb62f47f 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -27,12 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive public abstract class BaseProgressiveStreamingService : BaseStreamingService { protected readonly IImageProcessor ImageProcessor; - protected readonly IHttpClient HttpClient; protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer) { ImageProcessor = imageProcessor; - HttpClient = httpClient; } /// diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ef0282abc..019f378c5 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -225,7 +225,7 @@ namespace MediaBrowser.Api.Playback { try { - await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index deea63112..d917b7d6d 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -101,6 +101,8 @@ namespace MediaBrowser.Controller.Entities public bool? IsMovie { get; set; } public bool? IsSports { get; set; } public bool? IsKids { get; set; } + public bool? IsNews { get; set; } + public bool? IsSeries { get; set; } public int? MinPlayers { get; set; } public int? MaxPlayers { get; set; } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 1df77cdc9..c06470c5e 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -92,8 +92,7 @@ namespace MediaBrowser.Controller.Library /// Closes the media source. /// /// The live stream identifier. - /// The cancellation token. /// Task. - Task CloseLiveStream(string id, CancellationToken cancellationToken); + Task CloseLiveStream(string id); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 5b033af4a..56366e5a8 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -28,8 +28,7 @@ namespace MediaBrowser.Controller.Library /// Closes the media source. /// /// The live stream identifier. - /// The cancellation token. /// Task. - Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken); + Task CloseMediaSource(string liveStreamId); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 41c5dbdbb..d65d1ae30 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -220,9 +220,8 @@ namespace MediaBrowser.Controller.LiveTv /// Closes the live stream. /// /// The identifier. - /// The cancellation token. /// Task. - Task CloseLiveStream(string id, CancellationToken cancellationToken); + Task CloseLiveStream(string id); /// /// Gets the guide information. diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 3c8b964a2..89d035649 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -22,9 +22,8 @@ namespace MediaBrowser.Controller.LiveTv /// /// Gets the channels. /// - /// The cancellation token. /// Task<IEnumerable<ChannelInfo>>. - Task> GetChannels(CancellationToken cancellationToken); + Task> GetChannels(bool enableCache, CancellationToken cancellationToken); /// /// Gets the tuner infos. /// @@ -46,8 +45,6 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task<List<MediaSourceInfo>>. Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); - - string ApplyDuration(string streamPath, TimeSpan duration); } public interface IConfigurableTunerHost { diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 15d09d857..1bb198632 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; @@ -7,17 +8,27 @@ namespace MediaBrowser.Controller.LiveTv public class LiveStream { public MediaSourceInfo OriginalMediaSource { get; set; } - public MediaSourceInfo PublicMediaSource { get; set; } - public string Id { get; set; } + public MediaSourceInfo OpenedMediaSource { get; set; } + public DateTime DateOpened { get; set; } + public int ConsumerCount { get; set; } + public ITunerHost TunerHost { get; set; } + public string OriginalStreamId { get; set; } public LiveStream(MediaSourceInfo mediaSource) { OriginalMediaSource = mediaSource; - PublicMediaSource = mediaSource; - Id = mediaSource.Id; + OpenedMediaSource = mediaSource; } - public virtual Task Open(CancellationToken cancellationToken) + public async Task Open(CancellationToken cancellationToken) + { + await OpenInternal(cancellationToken).ConfigureAwait(false); + DateOpened = DateTime.UtcNow; + + OpenedMediaSource.DateLiveStreamOpened = DateOpened; + } + + protected virtual Task OpenInternal(CancellationToken cancellationToken) { return Task.FromResult(true); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 50aeed27d..69a1c24ea 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -9,7 +9,7 @@ using System.Runtime.Serialization; namespace MediaBrowser.Controller.LiveTv { - public class LiveTvChannel : BaseItem, IHasMediaSources + public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes { public override List GetUserDataKeys() { @@ -137,5 +137,56 @@ namespace MediaBrowser.Controller.LiveTv { return false; } + + [IgnoreDataMember] + public bool IsMovie { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is sports. + /// + /// true if this instance is sports; otherwise, false. + [IgnoreDataMember] + public bool IsSports { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is series. + /// + /// true if this instance is series; otherwise, false. + [IgnoreDataMember] + public bool IsSeries { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is live. + /// + /// true if this instance is live; otherwise, false. + [IgnoreDataMember] + public bool IsLive { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is news. + /// + /// true if this instance is news; otherwise, false. + [IgnoreDataMember] + public bool IsNews { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is kids. + /// + /// true if this instance is kids; otherwise, false. + [IgnoreDataMember] + public bool IsKids { get; set; } + + [IgnoreDataMember] + public bool IsPremiere { get; set; } + + [IgnoreDataMember] + public bool IsRepeat { get; set; } + + /// + /// Gets or sets the episode title. + /// + /// The episode title. + [IgnoreDataMember] + public string EpisodeTitle { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index 42c3480ce..978e9e1a8 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -101,6 +101,7 @@ namespace MediaBrowser.Controller.LiveTv public bool IsMovie { get; set; } public bool IsKids { get; set; } public bool IsSports { get; set; } + public bool IsNews { get; set; } public int? ProductionYear { get; set; } public string EpisodeTitle { get; set; } public DateTime? OriginalAirDate { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index 490a51128..d3738d903 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index bb07d9cb6..2be69c8e4 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using System; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.MediaInfo; using System.Collections.Generic; @@ -52,7 +53,9 @@ namespace MediaBrowser.Model.Dto public string TranscodingUrl { get; set; } public string TranscodingSubProtocol { get; set; } public string TranscodingContainer { get; set; } - + + public DateTime? DateLiveStreamOpened { get; set; } + public MediaSourceInfo() { Formats = new List(); diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 0ece1e4a0..f76368a7b 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -61,6 +61,30 @@ namespace MediaBrowser.Model.LiveTv public bool AddCurrentProgram { get; set; } public bool EnableUserData { get; set; } + /// + /// Used to specific whether to return news or not + /// + /// If set to null, all programs will be returned + public bool? IsNews { get; set; } + + /// + /// Used to specific whether to return movies or not + /// + /// If set to null, all programs will be returned + public bool? IsMovie { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is kids. + /// + /// null if [is kids] contains no value, true if [is kids]; otherwise, false. + public bool? IsKids { get; set; } + /// + /// Gets or sets a value indicating whether this instance is sports. + /// + /// null if [is sports] contains no value, true if [is sports]; otherwise, false. + public bool? IsSports { get; set; } + public bool? IsSeries { get; set; } + public LiveTvChannelQuery() { EnableUserData = true; diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index bf459237a..7886342e7 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -62,6 +62,12 @@ namespace MediaBrowser.Model.LiveTv /// public DateTime? MaxEndDate { get; set; } + /// + /// Used to specific whether to return news or not + /// + /// If set to null, all programs will be returned + public bool? IsNews { get; set; } + /// /// Used to specific whether to return movies or not /// @@ -83,6 +89,7 @@ namespace MediaBrowser.Model.LiveTv /// Skips over a given number of items within the results. Use for paging. /// public int? StartIndex { get; set; } + public bool? IsSeries { get; set; } /// /// Gets or sets a value indicating whether this instance has aired. diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 0e6d081a1..4bc506bf6 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -45,11 +45,17 @@ namespace MediaBrowser.Model.LiveTv /// The limit. public int? Limit { get; set; } + /// + /// Gets or sets a value indicating whether this instance is movie. + /// + /// null if [is movie] contains no value, true if [is movie]; otherwise, false. + public bool? IsNews { get; set; } /// /// Gets or sets a value indicating whether this instance is movie. /// /// null if [is movie] contains no value, true if [is movie]; otherwise, false. public bool? IsMovie { get; set; } + public bool? IsSeries { get; set; } /// /// Gets or sets a value indicating whether this instance is kids. /// diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index 0ba5f1779..265aad335 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -68,6 +68,7 @@ namespace MediaBrowser.Model.LiveTv /// The fields. public ItemFields[] Fields { get; set; } public bool? EnableImages { get; set; } + public bool? IsNews { get; set; } public bool? IsMovie { get; set; } public bool? IsSeries { get; set; } public bool? IsKids { get; set; } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs index 3239b20b2..6cba1b441 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Channels throw new NotImplementedException(); } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index c20245a6e..c7650102f 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -355,7 +355,7 @@ namespace MediaBrowser.Server.Implementations.Library .ToList(); } - private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _openStreams = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); public async Task OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken) @@ -383,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.Library Id = mediaSource.LiveStreamId, MediaSource = mediaSource }; - _openStreams.AddOrUpdate(mediaSource.LiveStreamId, info, (key, i) => info); + _openStreams[mediaSource.LiveStreamId] = info; if (enableAutoClose) { @@ -421,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("id"); } - _logger.Debug("Getting live stream {0}", id); + _logger.Debug("Getting already opened live stream {0}", id); await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -465,17 +465,16 @@ namespace MediaBrowser.Server.Implementations.Library } } - private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId, CancellationToken cancellationToken) + private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId) { _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name); try { - await provider.CloseMediaSource(streamId, cancellationToken).ConfigureAwait(false); + await provider.CloseMediaSource(streamId).ConfigureAwait(false); } catch (NotImplementedException) { - } catch (Exception ex) { @@ -483,37 +482,35 @@ namespace MediaBrowser.Server.Implementations.Library } } - public async Task CloseLiveStream(string id, CancellationToken cancellationToken) + public async Task CloseLiveStream(string id) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException("id"); } - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); try { LiveStreamInfo current; + if (_openStreams.TryGetValue(id, out current)) { + _openStreams.Remove(id); + current.Closed = true; + if (current.MediaSource.RequiresClosing) { var tuple = GetProvider(id); - await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false); + await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false); } - } - LiveStreamInfo removed; - if (_openStreams.TryRemove(id, out removed)) - { - removed.Closed = true; - } - - if (_openStreams.Count == 0) - { - StopCloseTimer(); + if (_openStreams.Count == 0) + { + StopCloseTimer(); + } } } finally @@ -565,10 +562,20 @@ namespace MediaBrowser.Server.Implementations.Library private async void CloseTimerCallback(object state) { - var infos = _openStreams - .Values - .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge) - .ToList(); + List infos; + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); + + try + { + infos = _openStreams + .Values + .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge) + .ToList(); + } + finally + { + _liveStreamSemaphore.Release(); + } foreach (var info in infos) { @@ -576,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Library { try { - await CloseLiveStream(info.Id, CancellationToken.None).ConfigureAwait(false); + await CloseLiveStream(info.Id).ConfigureAwait(false); } catch (Exception ex) { @@ -608,12 +615,10 @@ namespace MediaBrowser.Server.Implementations.Library { foreach (var key in _openStreams.Keys.ToList()) { - var task = CloseLiveStream(key, CancellationToken.None); + var task = CloseLiveStream(key); Task.WaitAll(task); } - - _openStreams.Clear(); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 0d043669a..0f8c15e71 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -47,19 +47,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _logger.Info("Copying recording stream to file {0}", targetFile); - if (mediaSource.RunTimeTicks.HasValue) - { - // The media source already has a fixed duration - // But add another stop 1 minute later just in case the recording gets stuck for any reason - var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1))); - cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - } - else - { - // The media source if infinite so we need to handle stopping ourselves - var durationToken = new CancellationTokenSource(duration); - cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - } + // The media source if infinite so we need to handle stopping ourselves + var durationToken = new CancellationTokenSource(duration); + cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; await CopyUntilCancelled(response.Content, output, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index f53ec3ee8..ef19dcbc9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -340,22 +340,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _timerProvider.Delete(timer); } - private List _channelCache = null; private async Task> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken) { - if (enableCache && _channelCache != null) - { - - return _channelCache.ToList(); - } - var list = new List(); foreach (var hostInstance in _liveTvManager.TunerHosts) { try { - var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.GetChannels(enableCache, cancellationToken).ConfigureAwait(false); list.AddRange(channels); } @@ -388,7 +381,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - _channelCache = list.ToList(); return list; } @@ -400,7 +392,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { try { - var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.GetChannels(false, cancellationToken).ConfigureAwait(false); list.AddRange(channels); } @@ -632,6 +624,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV existingTimer.Genres = updatedTimer.Genres; existingTimer.HomePageUrl = updatedTimer.HomePageUrl; existingTimer.IsKids = updatedTimer.IsKids; + existingTimer.IsNews = updatedTimer.IsNews; existingTimer.IsMovie = updatedTimer.IsMovie; existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries; existingTimer.IsSports = updatedTimer.IsSports; @@ -836,33 +829,68 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var result = await GetChannelStreamInternal(channelId, streamId, cancellationToken).ConfigureAwait(false); - return result.Item1.PublicMediaSource; + return result.Item2; + } + + private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId) + { + var json = _jsonSerializer.SerializeToString(mediaSource); + mediaSource = _jsonSerializer.DeserializeFromString(json); + + mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id; + + return mediaSource; } - private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) + private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) { _logger.Info("Streaming Channel " + channelId); - foreach (var hostInstance in _liveTvManager.TunerHosts) + await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase)); + + if (result != null) { - try - { - var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); + //result.ConsumerCount++; - await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false); - _liveStreams[result.Id] = result; - _liveStreamsSemaphore.Release(); + //_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); - return new Tuple(result, hostInstance); - } - catch (FileNotFoundException) - { - } - catch (Exception e) + //_liveStreamsSemaphore.Release(); + //return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost); + } + + try + { + foreach (var hostInstance in _liveTvManager.TunerHosts) { - _logger.ErrorException("Error getting channel stream", e); + try + { + result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); + + _liveStreams[result.OpenedMediaSource.Id] = result; + + result.ConsumerCount++; + result.TunerHost = hostInstance; + result.OriginalStreamId = streamId; + + _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}", + streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId); + + return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance); + } + catch (FileNotFoundException) + { + } + catch (OperationCanceledException) + { + } } } + finally + { + _liveStreamsSemaphore.Release(); + } throw new ApplicationException("Tuner not found."); } @@ -896,25 +924,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task CloseLiveStream(string id, CancellationToken cancellationToken) { - await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false); + // Ignore the consumer id + id = id.Substring(id.IndexOf('_') + 1); + + await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { LiveStream stream; if (_liveStreams.TryGetValue(id, out stream)) { - _liveStreams.Remove(id); + stream.ConsumerCount--; - try + _logger.Info("Live stream {0} consumer count is now {1}", id, stream.ConsumerCount); + + if (stream.ConsumerCount <= 0) { + _liveStreams.Remove(id); + + _logger.Info("Closing live stream {0}", id); + await stream.Close().ConfigureAwait(false); _logger.Info("Live stream {0} closed successfully", id); } - catch (Exception ex) - { - _logger.ErrorException("Error closing live stream", ex); - } } + else + { + _logger.Warn("Live stream not found: {0}, unable to close", id); + } + } + catch (OperationCanceledException) + { + } + catch (Exception ex) + { + _logger.ErrorException("Error closing live stream", ex); } finally { @@ -1095,20 +1139,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var recordPath = GetRecordingPath(timer, out seriesPath); var recordingStatus = RecordingStatus.New; - LiveStream liveStream = null; + string liveStreamId = null; try { var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); - var liveStreamInfo = - await - GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) + var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) .ConfigureAwait(false); - liveStream = liveStreamInfo.Item1; - var mediaStreamInfo = liveStreamInfo.Item1.PublicMediaSource; - var tunerHost = liveStreamInfo.Item2; + + var mediaStreamInfo = liveStreamInfo.Item2; + liveStreamId = mediaStreamInfo.Id; // HDHR doesn't seem to release the tuner right away after first probing with ffmpeg //await Task.Delay(3000, cancellationToken).ConfigureAwait(false); @@ -1140,15 +1182,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV EnforceKeepUpTo(timer); }; - var pathWithDuration = tunerHost.ApplyDuration(mediaStreamInfo.Path, duration); - - // If it supports supplying duration via url - if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase)) - { - mediaStreamInfo.Path = pathWithDuration; - mediaStreamInfo.RunTimeTicks = duration.Ticks; - } - await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken) .ConfigureAwait(false); @@ -1166,11 +1199,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recordingStatus = RecordingStatus.Error; } - if (liveStream != null) + if (!string.IsNullOrWhiteSpace(liveStreamId)) { try { - await CloseLiveStream(liveStream.Id, CancellationToken.None).ConfigureAwait(false); + await CloseLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -1251,7 +1284,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1); private async Task DeleteLibraryItemsForTimers(List timers) { foreach (var timer in timers) @@ -1295,7 +1328,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } catch (FileNotFoundException) { - + } } @@ -1492,6 +1525,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { AddGenre(timer.Genres, "Kids"); } + if (timer.IsNews) + { + AddGenre(timer.Genres, "News"); + } foreach (var genre in timer.Genres) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index f74a76e3f..ce5f14f4b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -71,38 +71,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var durationToken = new CancellationTokenSource(duration); cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; - await RecordFromFile(mediaSource, mediaSource.Path, targetFile, false, duration, onStarted, cancellationToken).ConfigureAwait(false); + await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false); _logger.Info("Recording completed to file {0}", targetFile); } - private async void DeleteTempFile(string path) - { - for (var i = 0; i < 10; i++) - { - try - { - File.Delete(path); - return; - } - catch (FileNotFoundException) - { - return; - } - catch (DirectoryNotFoundException) - { - return; - } - catch (Exception ex) - { - _logger.ErrorException("Error deleting recording temp file", ex); - } - - await Task.Delay(1000).ConfigureAwait(false); - } - } - - private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, bool deleteInputFileAfterCompletion, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) + private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { _targetPath = targetFile; _fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile)); @@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); _logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length); - process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile, deleteInputFileAfterCompletion); + process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile); process.Start(); @@ -252,7 +226,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV /// /// Processes the exited. /// - private void OnFfMpegProcessExited(Process process, string inputFile, bool deleteInputFileAfterCompletion) + private void OnFfMpegProcessExited(Process process, string inputFile) { _hasExited = true; @@ -278,11 +252,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _logger.Error("FFMpeg recording exited with an error for {0}.", _targetPath); _taskCompletionSource.TrySetException(new Exception(string.Format("Recording for {0} failed", _targetPath))); } - - if (deleteInputFileAfterCompletion) - { - DeleteTempFile(inputFile); - } } private void DisposeLogStream() diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index f9c04abc5..bb6935e8e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV timerInfo.EpisodeNumber = programInfo.EpisodeNumber; timerInfo.IsMovie = programInfo.IsMovie; timerInfo.IsKids = programInfo.IsKids; + timerInfo.IsNews = programInfo.IsNews; timerInfo.IsSports = programInfo.IsSports; timerInfo.ProductionYear = programInfo.ProductionYear; timerInfo.EpisodeTitle = programInfo.EpisodeTitle; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 8a4572813..7c61d2396 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -62,9 +62,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly List _services = new List(); - private readonly ConcurrentDictionary _openStreams = - new ConcurrentDictionary(); - private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1); private readonly List _tunerHosts = new List(); @@ -153,6 +150,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channels = _libraryManager.GetItemList(new InternalItemsQuery { + IsMovie = query.IsMovie, + IsNews = query.IsNews, + IsKids = query.IsKids, + IsSports = query.IsSports, + IsSeries = query.IsSeries, IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }, SortBy = new[] { ItemSortBy.SortName }, TopParentIds = new[] { topFolder.Id.ToString("N") } @@ -407,15 +409,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info)); Normalize(info, service, isVideo); - var data = new LiveStreamData - { - Info = info, - IsChannel = isChannel, - ItemId = id - }; - - _openStreams.AddOrUpdate(info.Id, data, (key, i) => data); - return info; } catch (Exception ex) @@ -937,8 +930,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv MaxStartDate = query.MaxStartDate, ChannelIds = query.ChannelIds, IsMovie = query.IsMovie, + IsSeries = query.IsSeries, IsSports = query.IsSports, IsKids = query.IsKids, + IsNews = query.IsNews, Genres = query.Genres, StartIndex = query.StartIndex, Limit = query.Limit, @@ -985,7 +980,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, IsAiring = query.IsAiring, + IsNews = query.IsNews, IsMovie = query.IsMovie, + IsSeries = query.IsSeries, IsSports = query.IsSports, IsKids = query.IsKids, EnableTotalRecordCount = query.EnableTotalRecordCount, @@ -1014,7 +1011,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var programList = programs.ToList(); - var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false); + var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false) || (query.IsNews ?? false) || (query.IsSeries ?? false); programs = programList.OrderBy(i => i.StartDate.Date) .ThenByDescending(i => GetRecommendationScore(i, user.Id, factorChannelWatchCount)) @@ -1305,6 +1302,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv var start = DateTime.UtcNow.AddHours(-1); var end = start.AddDays(guideDays); + var isMovie = false; + var isSports = false; + var isNews = false; + var isKids = false; + var iSSeries = false; + var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false); foreach (var program in channelPrograms) @@ -1312,7 +1315,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv var programItem = await GetProgram(program, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false); programs.Add(programItem.Id); + + if (program.IsMovie) + { + isMovie = true; + } + + if (program.IsSeries) + { + iSSeries = true; + } + + if (program.IsSports) + { + isSports = true; + } + + if (program.IsNews) + { + isNews = true; + } + + if (program.IsKids) + { + isKids = true; + } } + + currentChannel.IsMovie = isMovie; + currentChannel.IsNews = isNews; + currentChannel.IsSports = isSports; + currentChannel.IsKids = isKids; + currentChannel.IsSeries = iSSeries; + + await currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -1647,6 +1683,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv recordings = recordings.Where(i => i.IsMovie == val); } + if (query.IsNews.HasValue) + { + var val = query.IsNews.Value; + recordings = recordings.Where(i => i.IsNews == val); + } + if (query.IsSeries.HasValue) { var val = query.IsSeries.Value; @@ -2444,9 +2486,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv internal bool IsChannel; } - public async Task CloseLiveStream(string id, CancellationToken cancellationToken) + public async Task CloseLiveStream(string id) { - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false); try { @@ -2461,12 +2503,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv id = parts[1]; - LiveStreamData data; - _openStreams.TryRemove(id, out data); - _logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id); - await service.CloseLiveStream(id, cancellationToken).ConfigureAwait(false); + await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -2500,7 +2539,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv Dispose(true); } - private readonly object _disposeLock = new object(); private bool _isDisposed = false; /// /// Releases unmanaged and - optionally - managed resources. @@ -2511,18 +2549,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (dispose) { _isDisposed = true; - - lock (_disposeLock) - { - foreach (var stream in _openStreams.Values.ToList()) - { - var task = CloseLiveStream(stream.Info.Id, CancellationToken.None); - - Task.WaitAll(task); - } - - _openStreams.Clear(); - } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index cdba1873e..aacc0c22b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -204,9 +204,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { - return _liveTvManager.CloseLiveStream(liveStreamId, cancellationToken); + return _liveTvManager.CloseLiveStream(liveStreamId); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 6beea352a..a4236763f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts .ToList(); } - public async Task> GetChannels(CancellationToken cancellationToken) + public async Task> GetChannels(bool enableCache, CancellationToken cancellationToken) { var list = new List(); @@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { try { - var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false); + var channels = await GetChannels(host, enableCache, cancellationToken).ConfigureAwait(false); var newChannels = channels.Where(i => !list.Any(l => string.Equals(i.Id, l.Id, StringComparison.OrdinalIgnoreCase))).ToList(); list.AddRange(newChannels); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b40b74436..9f71940e1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -67,14 +67,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return id; } - public string ApplyDuration(string streamPath, TimeSpan duration) - { - streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&"; - streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture); - - return streamPath; - } - private async Task> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) { var options = new HttpRequestOptions diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs index d3540d180..d6574db22 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun _appHost = appHost; } - public override async Task Open(CancellationToken openCancellationToken) + protected override async Task OpenInternal(CancellationToken openCancellationToken) { _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested(); @@ -54,13 +54,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun await taskCompletionSource.Task.ConfigureAwait(false); - PublicMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts"; + OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts"; - PublicMediaSource.Protocol = MediaProtocol.Http; + OpenedMediaSource.Protocol = MediaProtocol.Http; } public override Task Close() { + _logger.Info("Closing HDHR live stream"); _liveStreamCancellationTokenSource.Cancel(); return _liveStreamTaskCompletionSource.Task; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index d9c0bb8bf..e5d6102b1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -153,10 +153,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { return Task.FromResult(true); } - - public string ApplyDuration(string streamPath, TimeSpan duration) - { - return streamPath; - } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 05c282687..097118418 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2530,38 +2530,111 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("IsOffline=@IsOffline"); cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline; } - if (query.IsMovie.HasValue) + + var exclusiveProgramAttribtues = !(query.IsMovie ?? true) || + !(query.IsSports ?? true) || + !(query.IsKids ?? true) || + !(query.IsNews ?? true) || + !(query.IsSeries ?? true); + + if (exclusiveProgramAttribtues) { - var alternateTypes = new List(); - if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + if (query.IsMovie.HasValue) + { + var alternateTypes = new List(); + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + { + alternateTypes.Add(typeof(Movie).FullName); + } + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + { + alternateTypes.Add(typeof(Trailer).FullName); + } + + if (alternateTypes.Count == 0) + { + whereClauses.Add("IsMovie=@IsMovie"); + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; + } + else + { + whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; + } + } + if (query.IsSeries.HasValue) { - alternateTypes.Add(typeof(Movie).FullName); + whereClauses.Add("IsSeries=@IsSeries"); + cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = query.IsSeries; } - if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + if (query.IsNews.HasValue) { - alternateTypes.Add(typeof(Trailer).FullName); + whereClauses.Add("IsNews=@IsNews"); + cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = query.IsNews; } - - if (alternateTypes.Count == 0) + if (query.IsKids.HasValue) { - whereClauses.Add("IsMovie=@IsMovie"); + whereClauses.Add("IsKids=@IsKids"); + cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids; } - else + if (query.IsSports.HasValue) { - whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + whereClauses.Add("IsSports=@IsSports"); + cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; } - cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie; } - if (query.IsKids.HasValue) - { - whereClauses.Add("IsKids=@IsKids"); - cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids; - } - if (query.IsSports.HasValue) + else { - whereClauses.Add("IsSports=@IsSports"); - cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; + var programAttribtues = new List(); + if (query.IsMovie ?? false) + { + var alternateTypes = new List(); + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name)) + { + alternateTypes.Add(typeof(Movie).FullName); + } + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + { + alternateTypes.Add(typeof(Trailer).FullName); + } + + if (alternateTypes.Count == 0) + { + programAttribtues.Add("IsMovie=@IsMovie"); + } + else + { + programAttribtues.Add("(IsMovie is null OR IsMovie=@IsMovie)"); + } + + cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = true; + } + if (query.IsSports ?? false) + { + programAttribtues.Add("IsSports=@IsSports"); + cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = true; + } + if (query.IsNews ?? false) + { + programAttribtues.Add("IsNews=@IsNews"); + cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = true; + } + if (query.IsSeries ?? false) + { + programAttribtues.Add("IsSeries=@IsSeries"); + cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = true; + } + if (query.IsKids ?? false) + { + programAttribtues.Add("IsKids=@IsKids"); + cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = true; + } + if (programAttribtues.Count > 0) + { + whereClauses.Add("("+string.Join(" OR ", programAttribtues.ToArray())+")"); + } } + if (query.IsFolder.HasValue) { whereClauses.Add("IsFolder=@IsFolder"); diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 48f48cdcc..5857e9dbc 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Session { try { - await _mediaSourceManager.CloseLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false); } catch (Exception ex) { diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs index a2b5851ac..cb666b6ac 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken) + public Task CloseMediaSource(string liveStreamId) { throw new NotImplementedException(); } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 2f8b34879..4850b6fe0 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -289,7 +289,7 @@ namespace MediaBrowser.WebDashboard.Api return list; } - private List> GetDeployIgnoreFilenames() + private List> GetDeployIgnoreFilenames() { var list = new List>(); @@ -313,8 +313,11 @@ namespace MediaBrowser.WebDashboard.Api public async Task Get(GetDashboardPackage request) { - var path = Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, - "webclient-dump"); + var mode = request.Mode; + + var path = string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? + Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, "webclient-dump") + : "C:\\dev\\emby-web-mobile\\src"; try { @@ -333,8 +336,6 @@ namespace MediaBrowser.WebDashboard.Api var appVersion = _appHost.ApplicationVersion.ToString(); - var mode = request.Mode; - // Try to trim the output size a bit var bowerPath = Path.Combine(path, "bower_components"); @@ -372,11 +373,6 @@ namespace MediaBrowser.WebDashboard.Api // Delete things that are unneeded in an attempt to keep the output as trim as possible _fileSystem.DeleteDirectory(Path.Combine(path, "css", "images", "tour"), true); } - else - { - MinifyCssDirectory(path); - MinifyJsDirectory(path); - } await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion); @@ -444,78 +440,6 @@ namespace MediaBrowser.WebDashboard.Api } } - private void MinifyCssDirectory(string path) - { - foreach (var file in Directory.GetFiles(path, "*.css", SearchOption.AllDirectories)) - { - if (file.IndexOf(".min.", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - if (file.IndexOf("bower_", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - - try - { - var text = _fileSystem.ReadAllText(file, Encoding.UTF8); - - var result = new KristensenCssMinifier().Minify(text, false, Encoding.UTF8); - - if (result.Errors.Count > 0) - { - Logger.Error("Error minifying css: " + result.Errors[0].Message); - } - else - { - text = result.MinifiedContent; - _fileSystem.WriteAllText(file, text, Encoding.UTF8); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error minifying css", ex); - } - } - } - - private void MinifyJsDirectory(string path) - { - foreach (var file in Directory.GetFiles(path, "*.js", SearchOption.AllDirectories)) - { - if (file.IndexOf(".min.", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - if (file.IndexOf("bower_", StringComparison.OrdinalIgnoreCase) != -1) - { - continue; - } - - try - { - var text = _fileSystem.ReadAllText(file, Encoding.UTF8); - - var result = new CrockfordJsMinifier().Minify(text, false, Encoding.UTF8); - - if (result.Errors.Count > 0) - { - Logger.Error("Error minifying javascript: " + result.Errors[0].Message); - } - else - { - text = result.MinifiedContent; - _fileSystem.WriteAllText(file, text, Encoding.UTF8); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error minifying css", ex); - } - } - } - private async Task DumpHtml(string source, string destination, string mode, string culture, string appVersion) { foreach (var file in Directory.GetFiles(source, "*", SearchOption.TopDirectoryOnly)) @@ -528,7 +452,7 @@ namespace MediaBrowser.WebDashboard.Api private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion) { - using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, true).ConfigureAwait(false)) + using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, false).ConfigureAwait(false)) { using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read)) { -- cgit v1.2.3 From 911d9f4598e4cafe24a8eb6d40a0d95356d3437c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 2 Oct 2016 00:31:47 -0400 Subject: move more metadata settings to per library --- MediaBrowser.Api/StartupWizardService.cs | 6 ----- MediaBrowser.Controller/Entities/BaseItem.cs | 6 +++-- .../Entities/CollectionFolder.cs | 2 +- MediaBrowser.Model/Configuration/ChapterOptions.cs | 6 ----- MediaBrowser.Model/Configuration/LibraryOptions.cs | 4 ++++ .../MediaInfo/FFProbeVideoInfo.cs | 4 ++-- .../TV/MissingEpisodeProvider.cs | 2 +- .../TV/TheTVDB/TvdbPrescanTask.cs | 17 ++++++++------ .../Library/LibraryManager.cs | 27 ++++++++++++++-------- .../MediaEncoder/EncodingManager.cs | 26 ++------------------- .../Session/SessionManager.cs | 3 +-- 11 files changed, 42 insertions(+), 61 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 176b497d7..ebb3204a4 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -88,8 +88,6 @@ namespace MediaBrowser.Api var result = new StartupConfiguration { UICulture = _config.Configuration.UICulture, - EnableInternetProviders = _config.Configuration.EnableInternetProviders, - SaveLocalMeta = _config.Configuration.SaveLocalMeta, MetadataCountryCode = _config.Configuration.MetadataCountryCode, PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage }; @@ -123,8 +121,6 @@ namespace MediaBrowser.Api public void Post(UpdateStartupConfiguration request) { _config.Configuration.UICulture = request.UICulture; - _config.Configuration.EnableInternetProviders = request.EnableInternetProviders; - _config.Configuration.SaveLocalMeta = request.SaveLocalMeta; _config.Configuration.MetadataCountryCode = request.MetadataCountryCode; _config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage; _config.SaveConfiguration(); @@ -215,8 +211,6 @@ namespace MediaBrowser.Api public class StartupConfiguration { public string UICulture { get; set; } - public bool EnableInternetProviders { get; set; } - public bool SaveLocalMeta { get; set; } public string MetadataCountryCode { get; set; } public string PreferredMetadataLanguage { get; set; } public string LiveTvTunerType { get; set; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 492058f98..be88c535e 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -422,7 +422,7 @@ namespace MediaBrowser.Controller.Entities public virtual bool IsInternetMetadataEnabled() { - return ConfigurationManager.Configuration.EnableInternetProviders; + return LibraryManager.GetLibraryOptions(this).EnableInternetProviders; } public virtual bool CanDelete() @@ -1341,7 +1341,9 @@ namespace MediaBrowser.Controller.Entities return false; } - return ConfigurationManager.Configuration.SaveLocalMeta; + var libraryOptions = LibraryManager.GetLibraryOptions(this); + + return libraryOptions.SaveLocalMetadata; } /// diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 77d7ca7f2..04ba53263 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.Entities { LibraryOptions[path] = options; - options.SchemaVersion = 2; + options.SchemaVersion = 3; XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path)); } } diff --git a/MediaBrowser.Model/Configuration/ChapterOptions.cs b/MediaBrowser.Model/Configuration/ChapterOptions.cs index f9ff6b4f9..c7bb6f861 100644 --- a/MediaBrowser.Model/Configuration/ChapterOptions.cs +++ b/MediaBrowser.Model/Configuration/ChapterOptions.cs @@ -2,17 +2,11 @@ { public class ChapterOptions { - public bool EnableMovieChapterImageExtraction { get; set; } - public bool EnableEpisodeChapterImageExtraction { get; set; } - public bool EnableOtherVideoChapterImageExtraction { get; set; } - public bool DownloadMovieChapters { get; set; } public bool DownloadEpisodeChapters { get; set; } public string[] FetcherOrder { get; set; } public string[] DisabledFetchers { get; set; } - - public bool ExtractDuringLibraryScan { get; set; } public ChapterOptions() { diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 460ee0918..5f8c77ccd 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -11,11 +11,15 @@ public bool DownloadImagesInAdvance { get; set; } public MediaPathInfo[] PathInfos { get; set; } + public bool SaveLocalMetadata { get; set; } + public bool EnableInternetProviders { get; set; } + public LibraryOptions() { EnablePhotos = true; EnableRealtimeMonitor = true; PathInfos = new MediaPathInfo[] { }; + EnableInternetProviders = true; } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 0f8cf93fb..66fe7ea81 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -262,8 +262,8 @@ namespace MediaBrowser.Providers.MediaInfo NormalizeChapterNames(chapters); var libraryOptions = _libraryManager.GetLibraryOptions(video); - var extractDuringScan = chapterOptions.ExtractDuringLibraryScan; - if (libraryOptions != null && libraryOptions.SchemaVersion >= 2) + var extractDuringScan = false; + if (libraryOptions != null) { extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan; } diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index a12402f4f..9c212e8a0 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -118,7 +118,7 @@ namespace MediaBrowser.Providers.TV var hasNewEpisodes = false; - if (_config.Configuration.EnableInternetProviders && addNewItems) + if (addNewItems && !group.Any(i => !i.IsInternetMetadataEnabled())) { var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs index 215e0640f..d9e1037d8 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs @@ -74,12 +74,6 @@ namespace MediaBrowser.Providers.TV /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - if (!_config.Configuration.EnableInternetProviders) - { - progress.Report(100); - return; - } - var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase)); if (seriesConfig != null && seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase)) @@ -116,7 +110,9 @@ namespace MediaBrowser.Providers.TV IncludeItemTypes = new[] { typeof(Series).Name }, Recursive = true, GroupByPresentationUniqueKey = false - }).Cast(); + + }).Cast() + .ToList(); var seriesIdsInLibrary = seriesList .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb))) @@ -126,6 +122,13 @@ namespace MediaBrowser.Providers.TV var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase) .ToList(); + var enableInternetProviders = seriesList.Count == 0 ? false : seriesList[0].IsInternetMetadataEnabled(); + if (!enableInternetProviders) + { + progress.Report(100); + return; + } + // If this is our first time, update all series if (string.IsNullOrEmpty(lastUpdateTime)) { diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index f6fb158ae..93ee91c21 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1216,12 +1216,7 @@ namespace MediaBrowser.Server.Implementations.Library if (libraryFolder != null) { info.ItemId = libraryFolder.Id.ToString("N"); - } - - var collectionFolder = libraryFolder as CollectionFolder; - if (collectionFolder != null) - { - info.LibraryOptions = collectionFolder.GetLibraryOptions(); + info.LibraryOptions = GetLibraryOptions(libraryFolder); } return info; @@ -1889,11 +1884,23 @@ namespace MediaBrowser.Server.Implementations.Library public LibraryOptions GetLibraryOptions(BaseItem item) { - var collectionFolder = GetCollectionFolders(item) - .OfType() - .FirstOrDefault(); + var collectionFolder = item as CollectionFolder; + if (collectionFolder == null) + { + collectionFolder = GetCollectionFolders(item) + .OfType() + .FirstOrDefault(); + } + + var options = collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions(); + + if (options.SchemaVersion < 3) + { + options.SaveLocalMetadata = ConfigurationManager.Configuration.SaveLocalMeta; + options.EnableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders; + } - return collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions(); + return options; } public string GetContentType(BaseItem item) diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs index 06c109dfc..21e847c68 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder } var libraryOptions = _libraryManager.GetLibraryOptions(video); - if (libraryOptions != null && libraryOptions.SchemaVersion >= 2) + if (libraryOptions != null) { if (!libraryOptions.EnableChapterImageExtraction) { @@ -70,29 +70,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder } else { - var options = _chapterManager.GetConfiguration(); - - if (video is Movie) - { - if (!options.EnableMovieChapterImageExtraction) - { - return false; - } - } - else if (video is Episode) - { - if (!options.EnableEpisodeChapterImageExtraction) - { - return false; - } - } - else - { - if (!options.EnableOtherVideoChapterImageExtraction) - { - return false; - } - } + return false; } // Can't extract images if there are no video streams diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index d2bdee9fa..2fcc76588 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -242,8 +242,7 @@ namespace MediaBrowser.Server.Implementations.Session var userLastActivityDate = user.LastActivityDate ?? DateTime.MinValue; user.LastActivityDate = activityDate; - // Don't log in the db anymore frequently than 10 seconds - if ((activityDate - userLastActivityDate).TotalSeconds > 10) + if ((activityDate - userLastActivityDate).TotalSeconds > 60) { try { -- cgit v1.2.3 From d5b5c8e1a5548f2f1321f0f9a63d86919de0b01e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 11 Oct 2016 02:46:59 -0400 Subject: update display of active recordings --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 +- .../Entities/AggregateFolder.cs | 9 ++ .../Entities/Audio/MusicAlbum.cs | 16 ++- .../Entities/Audio/MusicArtist.cs | 9 ++ MediaBrowser.Controller/Entities/BaseItem.cs | 9 ++ .../Entities/CollectionFolder.cs | 9 ++ MediaBrowser.Controller/Entities/Folder.cs | 9 ++ MediaBrowser.Controller/Entities/GameSystem.cs | 9 ++ MediaBrowser.Controller/Entities/IHasUserData.cs | 2 + MediaBrowser.Controller/Entities/Photo.cs | 4 +- MediaBrowser.Controller/Entities/PhotoAlbum.cs | 9 ++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 9 ++ MediaBrowser.Controller/Entities/UserView.cs | 9 ++ MediaBrowser.Controller/Entities/Video.cs | 9 ++ .../LiveTv/LiveTvVideoRecording.cs | 9 ++ .../MediaEncoding/IMediaEncoder.cs | 2 +- .../MediaEncoding/MediaInfoRequest.cs | 1 + MediaBrowser.Controller/Playlists/Playlist.cs | 9 ++ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 4 +- .../Encoder/EncodingUtils.cs | 15 ++- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 40 ++++++-- MediaBrowser.Model/MediaInfo/MediaProtocol.cs | 3 +- .../Dto/DtoService.cs | 2 +- .../Library/UserDataManager.cs | 3 +- .../LiveTv/EmbyTV/EmbyTV.cs | 54 ++++++---- .../LiveTv/LiveStreamHelper.cs | 110 +++++++++++++++++++++ .../LiveTv/LiveTvManager.cs | 19 ++++ .../LiveTv/LiveTvMediaSourceProvider.cs | 88 +---------------- .../MediaBrowser.Server.Implementations.csproj | 1 + .../Session/SessionManager.cs | 10 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 33 files changed, 361 insertions(+), 135 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs (limited to 'MediaBrowser.Server.Implementations/Session/SessionManager.cs') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index b5bef1ce9..0e91c0b9e 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -819,10 +819,10 @@ namespace MediaBrowser.Api.Playback { if (state.PlayableStreamFileNames.Count > 0) { - return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); } - return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol); } /// diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 9709813dc..7b769deb3 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.Entities return false; } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + /// /// The _virtual children /// diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 1f3b0c92a..3f457d89a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio /// public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IMetadataContainer { + public List AlbumArtists { get; set; } + public List Artists { get; set; } + public MusicAlbum() { Artists = new List(); @@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + [IgnoreDataMember] public override bool SupportsCumulativeRunTimeTicks { @@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio get { return false; } } - public List AlbumArtists { get; set; } - /// /// Gets the tracks. /// @@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio return Tracks; } - public List Artists { get; set; } - public override List GetUserDataKeys() { var list = base.GetUserDataKeys(); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 076a7031a..a31f04fc4 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio get { return true; } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override bool CanDelete() { return !IsAccessedByName; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cc4a8fdb9..7eb84fc80 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -129,6 +129,15 @@ namespace MediaBrowser.Controller.Entities get { return false; } } + [IgnoreDataMember] + public virtual bool SupportsPlayedStatus + { + get + { + return false; + } + } + public bool DetectIsInMixedFolder() { if (SupportsIsInMixedFolderDetection) diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 04ba53263..41e277b7c 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override bool CanDelete() { return false; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e5994fde5..993e36fd8 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -61,6 +61,15 @@ namespace MediaBrowser.Controller.Entities get { return false; } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return true; + } + } + /// /// Gets a value indicating whether this instance is folder. /// diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index 1c09ee507..9e00ab260 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + /// /// Gets or sets the game system. /// diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs index 2495b0ccd..c21e170ae 100644 --- a/MediaBrowser.Controller/Entities/IHasUserData.cs +++ b/MediaBrowser.Controller/Entities/IHasUserData.cs @@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user); bool EnableRememberingTrackSelections { get; } + + bool SupportsPlayedStatus { get; } } } diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 41e25e406..a42fce8bb 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -29,13 +29,13 @@ namespace MediaBrowser.Controller.Entities { get { - return Album; + return AlbumEntity; } } [IgnoreDataMember] - public PhotoAlbum Album + public PhotoAlbum AlbumEntity { get { diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index b0ddcfb8c..cb5c5c453 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index aff1f5e28..b67817846 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + private void ClearCache() { lock (_childIdsLock) diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 92f8e8a9d..a689e0d09 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities return list; } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return false; + } + } + public override int GetChildCount(User user) { return GetChildren(user, true).Count(); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index baf9293bf..e83d1298e 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return true; + } + } + public override string CreatePresentationUniqueKey() { if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index e26dd6a77..635df5dc7 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -54,6 +54,15 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return Status == RecordingStatus.Completed && base.SupportsPlayedStatus; + } + } + [IgnoreDataMember] public override LocationType LocationType { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index f97fe9560..866a08aa1 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// The input files. /// The protocol. /// System.String. - string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol); + string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol); /// /// Gets the input argument. diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index ca0c2fdbb..9ff7567d4 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding public IIsoMount MountedIso { get; set; } public VideoType VideoType { get; set; } public List PlayableStreamFileNames { get; set; } + public int AnalyzeDurationSections { get; set; } public MediaInfoRequest() { diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 654b97d7d..8e0ac7ea8 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists } } + [IgnoreDataMember] + public override bool SupportsPlayedStatus + { + get + { + return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase); + } + } + [IgnoreDataMember] public override bool AlwaysScanInternalMetadataPath { diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index f1e2f7241..c7b78aae3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -431,10 +431,10 @@ namespace MediaBrowser.MediaEncoding.Encoder { if (state.PlayableStreamFileNames.Count > 0) { - return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); } - return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); + return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol); } /// diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 5d0f1f075..cec272b39 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -26,6 +26,12 @@ namespace MediaBrowser.MediaEncoding.Encoder return string.Format("\"{0}\"", url); } + if (protocol == MediaProtocol.Udp) + { + var url = inputFiles.First(); + + return string.Format("\"{0}\"", url); + } return GetConcatInputArgument(inputFiles); } @@ -74,9 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder return path.Replace("\"", "\\\""); } - public static string GetProbeSizeArgument(bool isDvd) + public static string GetProbeSizeArgument(int numInputFiles) + { + return numInputFiles > 1 ? "-probesize 1G" : ""; + } + + public static string GetAnalyzeDurationArgument(int numInputFiles) { - return isDvd ? "-probesize 1G -analyzeduration 200M" : ""; + return numInputFiles > 1 ? "-analyzeduration 200M" : ""; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 5c3345008..fc1444e1b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -426,10 +426,24 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); - var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol); + var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length); + string analyzeDuration; + + if (request.AnalyzeDurationSections > 0) + { + analyzeDuration = "-analyzeduration " + + (request.AnalyzeDurationSections*1000000).ToString(CultureInfo.InvariantCulture); + } + else + { + analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length); + } + + probeSize = probeSize + " " + analyzeDuration; + probeSize = probeSize.Trim(); return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, - probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); + probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } /// @@ -450,9 +464,23 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The input files. /// The protocol. /// System.String. - public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol) + public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol) { - return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 1); + var results = new List(); + + var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length); + var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length); + + if (!string.IsNullOrWhiteSpace(probeSize)) + { + results.Add(probeSize); + } + + if (!string.IsNullOrWhiteSpace(analyzeDuration)) + { + results.Add(analyzeDuration); + } + return string.Join(" ", results.ToArray()); } /// @@ -871,7 +899,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) : string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); - var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); + var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol); if (!string.IsNullOrEmpty(probeSize)) { @@ -982,7 +1010,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); - var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol); + var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol); if (!string.IsNullOrEmpty(probeSize)) { diff --git a/MediaBrowser.Model/MediaInfo/MediaProtocol.cs b/MediaBrowser.Model/MediaInfo/MediaProtocol.cs index 880310814..1474e6d96 100644 --- a/MediaBrowser.Model/MediaInfo/MediaProtocol.cs +++ b/MediaBrowser.Model/MediaInfo/MediaProtocol.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo File = 0, Http = 1, Rtmp = 2, - Rtsp = 3 + Rtsp = 3, + Udp = 4 } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index b878226de..a0f7aa999 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -598,7 +598,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.Altitude = item.Altitude; dto.IsoSpeedRating = item.IsoSpeedRating; - var album = item.Album; + var album = item.AlbumEntity; if (album != null) { diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index ec8ac1a42..139ea0ab6 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -269,9 +269,10 @@ namespace MediaBrowser.Server.Implementations.Library positionTicks = 0; } - if (item is Audio) + if (!item.SupportsPlayedStatus) { positionTicks = 0; + data.Played = false; } data.PlaybackPositionTicks = positionTicks; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9781775d5..136a9e195 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -27,6 +27,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using CommonIO; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -59,8 +60,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public static EmbyTV Current; - public event EventHandler DataSourceChanged { add { } remove { } } - public event EventHandler RecordingStatusChanged { add { } remove { } } + public event EventHandler DataSourceChanged; + public event EventHandler RecordingStatusChanged; private readonly ConcurrentDictionary _activeRecordings = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); @@ -1009,7 +1010,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV throw new NotImplementedException(); } - public Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) + public async Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) { ActiveRecordingInfo info; @@ -1017,22 +1018,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (_activeRecordings.TryGetValue(recordingId, out info)) { - return Task.FromResult(new List + var stream = new MediaSourceInfo + { + Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream", + Id = recordingId, + SupportsDirectPlay = false, + SupportsDirectStream = true, + SupportsTranscoding = true, + IsInfiniteStream = true, + RequiresOpening = false, + RequiresClosing = false, + Protocol = Model.MediaInfo.MediaProtocol.Http, + BufferMs = 0 + }; + + var isAudio = false; + await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); + + return new List { - new MediaSourceInfo - { - Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream", - Id = recordingId, - SupportsDirectPlay = false, - SupportsDirectStream = true, - SupportsTranscoding = true, - IsInfiniteStream = true, - RequiresOpening = false, - RequiresClosing = false, - Protocol = Model.MediaInfo.MediaProtocol.Http, - BufferMs = 0 - } - }); + stream + }; } throw new FileNotFoundException(); @@ -1258,6 +1264,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV string liveStreamId = null; + OnRecordingStatusChanged(); + try { var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); @@ -1353,6 +1361,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { _timerProvider.Delete(timer); } + + OnRecordingStatusChanged(); + } + + private void OnRecordingStatusChanged() + { + EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs + { + + }, _logger); } private async void EnforceKeepUpTo(TimerInfo timer) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs new file mode 100644 index 000000000..336c32bae --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs @@ -0,0 +1,110 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Server.Implementations.LiveTv +{ + public class LiveStreamHelper + { + private readonly IMediaEncoder _mediaEncoder; + private readonly ILogger _logger; + + public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger) + { + _mediaEncoder = mediaEncoder; + _logger = logger; + } + + public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) + { + var originalRuntime = mediaSource.RunTimeTicks; + + var now = DateTime.UtcNow; + + var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + { + InputPath = mediaSource.Path, + Protocol = mediaSource.Protocol, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false, + AnalyzeDurationSections = 2 + + }, cancellationToken).ConfigureAwait(false); + + _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); + + mediaSource.Bitrate = info.Bitrate; + mediaSource.Container = info.Container; + mediaSource.Formats = info.Formats; + 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; + } + } + + // This is coming up false and preventing stream copy + videoStream.IsAVC = null; + } + + // Try to estimate this + if (!mediaSource.Bitrate.HasValue) + { + var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); + + if (total > 0) + { + mediaSource.Bitrate = total; + } + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index a295320ec..bac9789b5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -121,9 +121,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var service in _services) { service.DataSourceChanged += service_DataSourceChanged; + service.RecordingStatusChanged += Service_RecordingStatusChanged; } } + private void Service_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e) + { + _lastRecordingRefreshTime = DateTime.MinValue; + } + public List TunerHosts { get { return _tunerHosts; } @@ -2299,6 +2305,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false); + info.RecordAnyChannel = true; + info.RecordAnyTime = true; + info.Days = new List + { + DayOfWeek.Sunday, + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday, + DayOfWeek.Saturday + }; + info.Id = null; return new Tuple(info, service); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 521f33e1c..a62796036 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -146,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv } else { - await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); + await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); } } catch (Exception ex) @@ -216,92 +216,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) - { - var originalRuntime = mediaSource.RunTimeTicks; - - var now = DateTime.UtcNow; - - var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - InputPath = mediaSource.Path, - Protocol = mediaSource.Protocol, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); - - _logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); - - mediaSource.Bitrate = info.Bitrate; - mediaSource.Container = info.Container; - mediaSource.Formats = info.Formats; - 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; - } - } - - // This is coming up false and preventing stream copy - videoStream.IsAVC = null; - } - - // Try to estimate this - if (!mediaSource.Bitrate.HasValue) - { - var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); - - if (total > 0) - { - mediaSource.Bitrate = total; - } - } - } - - public Task CloseMediaSource(string liveStreamId) { return _liveTvManager.CloseLiveStream(liveStreamId); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 73e6ce1a5..f01a107df 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -234,6 +234,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 2fcc76588..e898a6abd 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -633,10 +633,14 @@ namespace MediaBrowser.Server.Implementations.Session data.PlayCount++; data.LastPlayedDate = DateTime.UtcNow; - if (!(item is Video)) + if (!(item is Video) && item.SupportsPlayedStatus) { data.Played = true; } + else + { + data.Played = false; + } await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); } @@ -847,11 +851,11 @@ namespace MediaBrowser.Server.Implementations.Session { playedToCompletion = _userDataManager.UpdatePlayState(item, data, positionTicks.Value); } - else + else { // If the client isn't able to report this, then we'll just have to make an assumption data.PlayCount++; - data.Played = true; + data.Played = item.SupportsPlayedStatus; data.PlaybackPositionTicks = 0; playedToCompletion = true; } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 2e4584fd4..1259a759b 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.661 + 3.0.662 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption. Copyright © Emby 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 56c616bd1..931db69fa 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.661 + 3.0.662 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 98a070c78..b3d929f59 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.661 + 3.0.662 Media Browser.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - + -- cgit v1.2.3