diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index c1a4fa765a..383d0881e9 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -74,6 +74,8 @@ namespace MediaBrowser.Controller.Providers /// The cancellation token. private void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, Encoding encoding, CancellationToken cancellationToken) { + item.ResetPeople(); + using (var streamReader = new StreamReader(metadataFile, encoding)) { // Use XmlReader for best performance @@ -492,7 +494,7 @@ namespace MediaBrowser.Controller.Providers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } break; } @@ -504,7 +506,7 @@ namespace MediaBrowser.Controller.Providers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } break; } @@ -529,7 +531,7 @@ namespace MediaBrowser.Controller.Providers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } } break; @@ -543,7 +545,7 @@ namespace MediaBrowser.Controller.Providers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } break; } @@ -1156,7 +1158,7 @@ namespace MediaBrowser.Controller.Providers { continue; } - PeopleHelper.AddPerson(item.People, person); + item.AddPerson(person); } } break; diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index a18dd83e83..68cdf4d725 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -10,9 +10,26 @@ namespace MediaBrowser.Controller.Providers public bool HasMetadata { get; set; } public T Item { get; set; } - public MetadataResult() + public void AddPerson(PersonInfo p) { - People = new List(); + if (People == null) + { + People = new List(); + } + + PeopleHelper.AddPerson(People, p); + } + + /// + /// Not only does this clear, but initializes the list so that services can differentiate between a null list and zero people + /// + public void ResetPeople() + { + if (People == null) + { + People = new List(); + } + People.Clear(); } } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index c3d1ec0809..9aa6485f10 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -194,6 +194,15 @@ namespace MediaBrowser.Providers.Manager return updateType; } + protected async Task SaveItem(MetadataResult result, ItemUpdateType reason, CancellationToken cancellationToken) + { + if (result.Item.SupportsPeople && result.People != null) + { + await LibraryManager.UpdatePeople(result.Item as BaseItem, result.People.ToList()); + } + await result.Item.UpdateToRepository(reason, cancellationToken).ConfigureAwait(false); + } + private readonly Task _cachedTask = Task.FromResult(true); protected virtual Task AfterMetadataRefresh(TItemType item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) { @@ -328,15 +337,6 @@ namespace MediaBrowser.Providers.Manager return providers; } - protected async Task SaveItem(MetadataResult result, ItemUpdateType reason, CancellationToken cancellationToken) - { - if (result.Item.SupportsPeople) - { - await LibraryManager.UpdatePeople(result.Item as BaseItem, result.People); - } - await result.Item.UpdateToRepository(reason, cancellationToken).ConfigureAwait(false); - } - public bool CanRefresh(IHasMetadata item) { return item is TItemType; diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index a0a0493d54..fa4840f103 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -105,9 +105,9 @@ namespace MediaBrowser.Providers.Manager if (!lockedFields.Contains(MetadataFields.Cast)) { - if (replaceData || targetResult.People.Count == 0) + if (replaceData || targetResult.People == null || targetResult.People.Count == 0) { - targetResult.People = sourceResult.People; + targetResult.People = sourceResult.People ?? new List(); } } diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 6854ff12bf..5b5afc6c73 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -231,13 +231,15 @@ namespace MediaBrowser.Providers.Movies movie.AddGenre(genre); } + resultItem.ResetPeople(); + //Actors, Directors, Writers - all in People //actors come from cast if (movieData.casts != null && movieData.casts.cast != null) { foreach (var actor in movieData.casts.cast.OrderBy(a => a.order)) { - PeopleHelper.AddPerson(resultItem.People, new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }); + resultItem.AddPerson(new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }); } } @@ -246,7 +248,7 @@ namespace MediaBrowser.Providers.Movies { foreach (var person in movieData.casts.crew) { - PeopleHelper.AddPerson(resultItem.People, new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = person.department }); + resultItem.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = person.department }); } } diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index f36de88c95..1702a50448 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -330,6 +330,8 @@ namespace MediaBrowser.Providers.TV { reader.MoveToContent(); + result.ResetPeople(); + // Loop through each element while (reader.Read()) { @@ -603,7 +605,7 @@ namespace MediaBrowser.Providers.TV .Where(i => !string.IsNullOrWhiteSpace(i)) .Select(str => new PersonInfo { Type = personType, Name = str.Trim() })) { - PeopleHelper.AddPerson(result.People, person); + result.AddPerson(person); } } @@ -632,7 +634,7 @@ namespace MediaBrowser.Providers.TV { if (!string.IsNullOrWhiteSpace(person.Name)) { - PeopleHelper.AddPerson(result.People, person); + result.AddPerson(person); } } } diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 4c93bd57c8..3298fbc76f 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -180,6 +180,8 @@ namespace MediaBrowser.Providers.TV cancellationToken.ThrowIfCancellationRequested(); + result.ResetPeople(); + FetchActors(result, actorsXmlPath); } @@ -721,7 +723,7 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrWhiteSpace(personInfo.Name)) { - PeopleHelper.AddPerson(result.People, personInfo); + result.AddPerson(personInfo); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index d9f1541c8c..50303a89a5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -73,14 +73,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + private async Task GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken) { string model = null; using (var stream = await _httpClient.Get(new HttpRequestOptions() { Url = string.Format("{0}/", GetApiUrl(info, false)), - CancellationToken = cancellationToken + CancellationToken = cancellationToken, + CacheLength = TimeSpan.FromDays(1), + CacheMode = CacheMode.Unconditional })) { using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) @@ -95,6 +97,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } + return null; + } + + public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + { + string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + using (var stream = await _httpClient.Get(new HttpRequestOptions() { Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), @@ -198,9 +207,79 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, string profile) { + int? width = null; + int? height = null; + bool isInterlaced = true; + var videoCodec = "mpeg2video"; + int? videoBitrate = null; + + if (string.Equals(profile, "mobile", StringComparison.OrdinalIgnoreCase)) + { + width = 1280; + height = 720; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 2000000; + } + else if (string.Equals(profile, "heavy", StringComparison.OrdinalIgnoreCase)) + { + width = 1920; + height = 1080; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 8000000; + } + else if (string.Equals(profile, "internet720", StringComparison.OrdinalIgnoreCase)) + { + width = 1280; + height = 720; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 5000000; + } + else if (string.Equals(profile, "internet540", StringComparison.OrdinalIgnoreCase)) + { + width = 1280; + height = 720; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 2500000; + } + else if (string.Equals(profile, "internet480", StringComparison.OrdinalIgnoreCase)) + { + width = 848; + height = 480; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 2000000; + } + else if (string.Equals(profile, "internet360", StringComparison.OrdinalIgnoreCase)) + { + width = 640; + height = 360; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 1500000; + } + else if (string.Equals(profile, "internet240", StringComparison.OrdinalIgnoreCase)) + { + width = 432; + height = 240; + isInterlaced = false; + videoCodec = "h264"; + videoBitrate = 1000000; + } + + var url = GetApiUrl(info, true) + "/auto/v" + channelId; + + if (!string.IsNullOrWhiteSpace(profile)) + { + url += "?transcode=" + profile; + } + var mediaSource = new MediaSourceInfo { - Path = GetApiUrl(info, true) + "/auto/v" + channelId, + Path = url, Protocol = MediaProtocol.Http, MediaStreams = new List { @@ -209,14 +288,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun Type = MediaStreamType.Video, // Set the index to -1 because we don't know the exact index of the video stream within the container Index = -1, - IsInterlaced = true + IsInterlaced = isInterlaced, + Codec = videoCodec, + Width = width, + Height = height, + BitRate = videoBitrate + }, new MediaStream { Type = MediaStreamType.Audio, // Set the index to -1 because we don't know the exact index of the audio stream within the container - Index = -1 - + Index = -1, + Codec = "ac3", + BitRate = 128000 } }, RequiresOpening = false, @@ -227,13 +312,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return mediaSource; } - public Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + public async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { var list = new List(); list.Add(GetMediaSource(info, channelId, null)); - return Task.FromResult(list); + try + { + string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + model = model ?? string.Empty; + + if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) + { + list.Add(GetMediaSource(info, channelId, "heavy")); + list.Add(GetMediaSource(info, channelId, "internet480")); + list.Add(GetMediaSource(info, channelId, "internet360")); + list.Add(GetMediaSource(info, channelId, "internet240")); + list.Add(GetMediaSource(info, channelId, "mobile")); + } + } + catch (Exception ex) + { + + } + + return list; } public async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index ad514492d7..d66d7ff19a 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -84,6 +84,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers /// The cancellation token. private void Fetch(LocalMetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) { + item.ResetPeople(); + if (!SupportsUrlAfterClosingXmlTag) { using (var streamReader = BaseNfoSaver.GetStreamReader(metadataFile)) @@ -574,7 +576,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } break; } @@ -593,7 +595,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } } break; @@ -607,7 +609,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers { continue; } - PeopleHelper.AddPerson(itemResult.People, p); + itemResult.AddPerson(p); } break; } @@ -618,7 +620,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers { var person = GetPersonFromXmlNode(subtree); - PeopleHelper.AddPerson(itemResult.People, person); + itemResult.AddPerson(person); } break; }