From b3de0249d8b97e305b064a45f6113d5b0d39f3bb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 Jul 2015 14:07:03 -0400 Subject: replace channel tabs --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index d1abda17e..0f99da8b4 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -772,20 +772,6 @@ namespace MediaBrowser.Model.Dlna } } - // Look for supported embedded subs that we can just mux into the output - foreach (SubtitleProfile profile in subtitleProfiles) - { - if (!profile.SupportsLanguage(subtitleStream.Language)) - { - continue; - } - - if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format)) - { - return profile; - } - } - return new SubtitleProfile { Method = SubtitleDeliveryMethod.Encode, -- cgit v1.2.3 From 3178896004540c4a5884b9235a67ffbe3f58af0b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 19 Jul 2015 23:43:13 -0400 Subject: update subtitle methods --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 ++-- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 4 ++-- .../MediaBrowser.MediaEncoding.csproj | 1 - MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 1 + .../Subtitles/ISubtitleParser.cs | 1 + .../Subtitles/ISubtitleWriter.cs | 1 + MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs | 3 ++- MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 1 + MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs | 1 + MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 1 + .../Subtitles/SubtitleTrackInfo.cs | 22 ---------------------- MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs | 1 + MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs | 1 + .../MediaBrowser.Model.Portable.csproj | 6 ++++++ .../MediaBrowser.Model.net35.csproj | 6 ++++++ MediaBrowser.Model/MediaBrowser.Model.csproj | 2 ++ MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs | 11 +++++++++++ MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs | 14 ++++++++++++++ .../Library/SearchEngine.cs | 2 +- .../Persistence/SqliteItemRepository.cs | 2 ++ .../MediaEncoding/Subtitles/AssParserTests.cs | 1 + .../MediaEncoding/Subtitles/SrtParserTests.cs | 1 + .../MediaEncoding/Subtitles/VttWriterTest.cs | 1 + MediaBrowser.WebDashboard/Api/PackageCreator.cs | 12 ++++++------ 24 files changed, 65 insertions(+), 35 deletions(-) delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/SubtitleTrackInfo.cs create mode 100644 MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs create mode 100644 MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index dc5858e86..e7885a3f8 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -689,7 +689,7 @@ namespace MediaBrowser.Api.Playback // TODO: Perhaps also use original_size=1920x800 ?? return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB", - subtitlePath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"), + subtitlePath.Replace('\\', '/').Replace(":/", "\\:/"), charsetParam, seconds.ToString(UsCulture)); } @@ -697,7 +697,7 @@ namespace MediaBrowser.Api.Playback var mediaPath = state.MediaPath ?? string.Empty; return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB", - mediaPath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"), + mediaPath.Replace('\\', '/').Replace(":/", "\\:/"), state.InternalSubtitleStreamOffset.ToString(UsCulture), seconds.ToString(UsCulture)); } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 97c5aecd0..fbfe79272 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -902,13 +902,13 @@ namespace MediaBrowser.MediaEncoding.Encoder // TODO: Perhaps also use original_size=1920x800 ?? return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB", - subtitlePath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"), + subtitlePath.Replace('\\', '/').Replace(":/", "\\:/"), charsetParam, seconds.ToString(UsCulture)); } return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB", - state.MediaPath.Replace('\\', '/').Replace("'", "\\'").Replace(":/", "\\:/"), + state.MediaPath.Replace('\\', '/').Replace(":/", "\\:/"), state.InternalSubtitleStreamOffset.ToString(UsCulture), seconds.ToString(UsCulture)); } diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index ad561c484..de05d9ffd 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -81,7 +81,6 @@ - diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index e711c02b6..6d723a087 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs index 5b072a450..75de81f46 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs index eb29e6c17..e28da9185 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs index a4fc5d795..474f712f9 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; using System.IO; using System.Text; using System.Threading; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index 9751176cb..d40d4afa7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Text.RegularExpressions; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs index 3e574f931..c05929fde 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs @@ -4,6 +4,7 @@ using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index bfc6c60fc..6c760658d 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Text; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleTrackInfo.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleTrackInfo.cs deleted file mode 100644 index 67d70ed6e..000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleTrackInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - public class SubtitleTrackInfo - { - public List TrackEvents { get; set; } - - public SubtitleTrackInfo() - { - TrackEvents = new List(); - } - } - - public class SubtitleTrackEvent - { - public string Id { get; set; } - public string Text { get; set; } - public long StartPositionTicks { get; set; } - public long EndPositionTicks { get; set; } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs index 955b36ecd..c32005f89 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index fa53e4d13..092add992 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index a1b7ce396..90a185a97 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -821,6 +821,12 @@ MediaInfo\SubtitleFormat.cs + + MediaInfo\SubtitleTrackEvent.cs + + + MediaInfo\SubtitleTrackInfo.cs + MediaInfo\TransportStreamTimestamp.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index d4a373733..e7878fb1b 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -777,6 +777,12 @@ MediaInfo\SubtitleFormat.cs + + MediaInfo\SubtitleTrackEvent.cs + + + MediaInfo\SubtitleTrackInfo.cs + MediaInfo\TransportStreamTimestamp.cs diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b36fa2362..5c7caf407 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -169,6 +169,8 @@ + + diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs new file mode 100644 index 000000000..b4ab6ed97 --- /dev/null +++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs @@ -0,0 +1,11 @@ + +namespace MediaBrowser.Model.MediaInfo +{ + public class SubtitleTrackEvent + { + public string Id { get; set; } + public string Text { get; set; } + public long StartPositionTicks { get; set; } + public long EndPositionTicks { get; set; } + } +} diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs new file mode 100644 index 000000000..765cfe32f --- /dev/null +++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Model.MediaInfo +{ + public class SubtitleTrackInfo + { + public List TrackEvents { get; set; } + + public SubtitleTrackInfo() + { + TrackEvents = new List(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index db8a2d4fd..abebd26cc 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Library }).Items; // Add search hints based on item name - hints.AddRange(mediaItems.Where(i => (user == null || i.IsVisibleStandalone(user)) && !(i is CollectionFolder)).Select(item => + hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && (user == null || i.IsVisibleStandalone(user)) && !(i is CollectionFolder)).Select(item => { var index = GetIndex(item.Name, searchTerm, terms); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 788d12cbb..9ce239eb9 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -1001,6 +1001,8 @@ namespace MediaBrowser.Server.Implementations.Persistence } dict["Recording"] = new[] { typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName }; + dict["Program"] = new[] { typeof(LiveTvProgram).FullName }; + dict["TvChannel"] = new[] { typeof(LiveTvChannel).FullName }; return dict; } diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs index 02fd66b20..d5a62802d 100644 --- a/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs @@ -1,5 +1,6 @@ using System.Text; using MediaBrowser.MediaEncoding.Subtitles; +using MediaBrowser.Model.MediaInfo; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs index 8ea4398e9..07717a328 100644 --- a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs @@ -4,6 +4,7 @@ using System.IO; using System.Threading; using MediaBrowser.MediaEncoding.Subtitles; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace MediaBrowser.Tests.MediaEncoding.Subtitles diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs index 7a4823ecf..924a1736f 100644 --- a/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Threading; using MediaBrowser.MediaEncoding.Subtitles; +using MediaBrowser.Model.MediaInfo; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace MediaBrowser.Tests.MediaEncoding.Subtitles { diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 7f7aa4a2d..3be24ddf1 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -304,11 +304,11 @@ namespace MediaBrowser.WebDashboard.Api } } - var version = GetType().Assembly.GetName().Version; + var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + appVersion : string.Empty; var imports = new[] { - "vulcanize-out.html?v=" + appVersion + "vulcanize-out.html" + versionString }; var importsHtml = string.Join("", imports.Select(i => "").ToArray()); @@ -316,7 +316,7 @@ namespace MediaBrowser.WebDashboard.Api // In chrome it is causing the body to be hidden while loading, which leads to width-check methods to return 0 for everything //imports = ""; - html = html.Replace("", "" + GetMetaTags(mode) + GetCommonCss(mode, version) + GetInitialJavascript(mode, version) + importsHtml + GetCommonJavascript(mode, version)); + html = html.Replace("", "" + GetMetaTags(mode) + GetCommonCss(mode, appVersion) + GetInitialJavascript(mode, appVersion) + importsHtml + GetCommonJavascript(mode, appVersion)); var bytes = Encoding.UTF8.GetBytes(html); @@ -412,7 +412,7 @@ namespace MediaBrowser.WebDashboard.Api /// The mode. /// The version. /// System.String. - private string GetCommonCss(string mode, Version version) + private string GetCommonCss(string mode, string version) { var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty; @@ -433,7 +433,7 @@ namespace MediaBrowser.WebDashboard.Api /// The mode. /// The version. /// System.String. - private string GetInitialJavascript(string mode, Version version) + private string GetInitialJavascript(string mode, string version) { var builder = new StringBuilder(); @@ -457,7 +457,7 @@ namespace MediaBrowser.WebDashboard.Api /// The mode. /// The version. /// System.String. - private string GetCommonJavascript(string mode, Version version) + private string GetCommonJavascript(string mode, string version) { var builder = new StringBuilder(); -- cgit v1.2.3 From 20b990dc9a01f00e561181ad48ae73d62bcb2427 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Jul 2015 14:32:55 -0400 Subject: start pulling in EmbyTV --- .../HttpClientManager/HttpClientManager.cs | 16 +- MediaBrowser.Controller/LiveTv/ChannelInfo.cs | 6 +- .../LiveTv/IListingsProvider.cs | 7 + MediaBrowser.Controller/LiveTv/ITunerHost.cs | 50 ++ .../MediaBrowser.Controller.csproj | 2 + MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 13 +- .../LiveTv/ChannelImageProvider.cs | 12 +- .../LiveTv/EmbyTV/EmbyTV.cs | 507 +++++++++++++++++++++ .../LiveTv/EmbyTV/ItemDataProvider.cs | 115 +++++ .../LiveTv/EmbyTV/RecordingHelper.cs | 119 +++++ .../LiveTv/EmbyTV/SeriesTimerManager.cs | 25 + .../LiveTv/EmbyTV/TimerManager.cs | 114 +++++ .../LiveTv/LiveTvManager.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun.cs | 205 +++++++++ .../LiveTv/TunerHosts/M3UTunerHost.cs | 189 ++++++++ .../MediaBrowser.Server.Implementations.csproj | 7 + 16 files changed, 1379 insertions(+), 10 deletions(-) create mode 100644 MediaBrowser.Controller/LiveTv/IListingsProvider.cs create mode 100644 MediaBrowser.Controller/LiveTv/ITunerHost.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index ae2148f08..7ca6f43d6 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -432,7 +432,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager var httpResponse = (HttpWebResponse)response; - EnsureSuccessStatusCode(httpResponse, options); + EnsureSuccessStatusCode(client, httpResponse, options); options.CancellationToken.ThrowIfCancellationRequested(); @@ -443,7 +443,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { var httpResponse = (HttpWebResponse)response; - EnsureSuccessStatusCode(httpResponse, options); + EnsureSuccessStatusCode(client, httpResponse, options); options.CancellationToken.ThrowIfCancellationRequested(); @@ -629,7 +629,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { var httpResponse = (HttpWebResponse)response; - EnsureSuccessStatusCode(httpResponse, options); + var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + EnsureSuccessStatusCode(client, httpResponse, options); options.CancellationToken.ThrowIfCancellationRequested(); @@ -803,13 +804,20 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return exception; } - private void EnsureSuccessStatusCode(HttpWebResponse response, HttpRequestOptions options) + private void EnsureSuccessStatusCode(HttpClientInfo client, HttpWebResponse response, HttpRequestOptions options) { var statusCode = response.StatusCode; + var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299; if (!isSuccessful) { + if ((int) statusCode == 429) + { + client.LastTimeout = DateTime.UtcNow; + } + + if (statusCode == HttpStatusCode.RequestEntityTooLarge) if (options.LogErrorResponseBody) { try diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index cdc9c76c8..32b8abdc5 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -48,6 +48,10 @@ namespace MediaBrowser.Controller.LiveTv /// /// null if [has image] contains no value, true if [has image]; otherwise, false. public bool? HasImage { get; set; } - + /// + /// Gets or sets a value indicating whether this instance is favorite. + /// + /// null if [is favorite] contains no value, true if [is favorite]; otherwise, false. + public bool? IsFavorite { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs new file mode 100644 index 000000000..2cef455e8 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -0,0 +1,7 @@ + +namespace MediaBrowser.Controller.LiveTv +{ + public interface IListingsProvider + { + } +} diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs new file mode 100644 index 000000000..2fa538c60 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -0,0 +1,50 @@ +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.LiveTv +{ + public interface ITunerHost + { + /// + /// Gets the name. + /// + /// The name. + string Name { get; } + /// + /// Gets the type. + /// + /// The type. + string Type { get; } + /// + /// Gets the tuner hosts. + /// + /// List<TunerHostInfo>. + List GetTunerHosts(); + /// + /// Gets the channels. + /// + /// The information. + /// The cancellation token. + /// Task<IEnumerable<ChannelInfo>>. + Task> GetChannels(TunerHostInfo info, CancellationToken cancellationToken); + /// + /// Gets the tuner infos. + /// + /// The information. + /// The cancellation token. + /// Task<List<LiveTvTunerInfo>>. + Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken); + /// + /// Gets the channel stream. + /// + /// The information. + /// The channel identifier. + /// The stream identifier. + /// The cancellation token. + /// Task<MediaSourceInfo>. + Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index fcde6d8c0..603f756af 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -198,7 +198,9 @@ + + diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c6f6ed84c..303b12af7 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -1,13 +1,24 @@ -namespace MediaBrowser.Model.LiveTv +using System.Collections.Generic; + +namespace MediaBrowser.Model.LiveTv { public class LiveTvOptions { public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } + public List TunerHosts { get; set; } + public string RecordingPath { get; set; } public LiveTvOptions() { EnableMovieProviders = true; + TunerHosts = new List(); } } + + public class TunerHostInfo + { + public string Url { get; set; } + public string Type { get; set; } + } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs index 7c3af0a54..f205da70d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Common; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; @@ -17,12 +18,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ILiveTvManager _liveTvManager; private readonly IHttpClient _httpClient; private readonly ILogger _logger; + private readonly IApplicationHost _appHost; - public ChannelImageProvider(ILiveTvManager liveTvManager, IHttpClient httpClient, ILogger logger) + public ChannelImageProvider(ILiveTvManager liveTvManager, IHttpClient httpClient, ILogger logger, IApplicationHost appHost) { _liveTvManager = liveTvManager; _httpClient = httpClient; _logger = logger; + _appHost = appHost; } public IEnumerable GetSupportedImages(IHasImages item) @@ -46,7 +49,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv var options = new HttpRequestOptions { CancellationToken = cancellationToken, - Url = liveTvItem.ProviderImageUrl + Url = liveTvItem.ProviderImageUrl, + + // Some image hosts require a user agent to be specified. + UserAgent = "Emby Server/" + _appHost.ApplicationVersion }; var response = await _httpClient.GetResponse(options).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs new file mode 100644 index 000000000..d0a271260 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -0,0 +1,507 @@ +using MediaBrowser.Common; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Events; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + public class EmbyTV : ILiveTvService, IDisposable + { + private readonly ILogger _logger; + private readonly IHttpClient _httpClient; + private readonly IConfigurationManager _config; + private readonly IJsonSerializer _jsonSerializer; + + private readonly List _tunerHosts = new List(); + private readonly ItemDataProvider _recordingProvider; + private readonly ItemDataProvider _seriesTimerProvider; + private readonly TimerManager _timerProvider; + + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) + { + _logger = logger; + _httpClient = httpClient; + _config = config; + _jsonSerializer = jsonSerializer; + _tunerHosts.AddRange(appHost.GetExports()); + + _recordingProvider = new ItemDataProvider(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); + _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); + _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers")); + _timerProvider.TimerFired += _timerProvider_TimerFired; + } + + public event EventHandler DataSourceChanged; + + public event EventHandler RecordingStatusChanged; + + private readonly ConcurrentDictionary _activeRecordings = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + public string Name + { + get { return "Emby"; } + } + + public string DataPath + { + get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "livetv"); } + } + + public string HomePageUrl + { + get { return "http://emby.media"; } + } + + public async Task GetStatusInfoAsync(CancellationToken cancellationToken) + { + var status = new LiveTvServiceStatusInfo(); + var list = new List(); + + foreach (var host in _tunerHosts) + { + foreach (var hostInstance in host.GetTunerHosts()) + { + try + { + var tuners = await host.GetTunerInfos(hostInstance, cancellationToken).ConfigureAwait(false); + + list.AddRange(tuners); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting tuners", ex); + } + } + } + + status.Tuners = list; + status.Status = LiveTvServiceStatus.Ok; + return status; + } + + public async Task> GetChannelsAsync(CancellationToken cancellationToken) + { + var list = new List(); + + foreach (var host in _tunerHosts) + { + foreach (var hostInstance in host.GetTunerHosts()) + { + try + { + var channels = await host.GetChannels(hostInstance, cancellationToken).ConfigureAwait(false); + + list.AddRange(channels); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channels", ex); + } + } + } + + return list; + } + + public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) + { + var remove = _seriesTimerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); + if (remove != null) + { + _seriesTimerProvider.Delete(remove); + } + return Task.FromResult(true); + } + + private void CancelTimerInternal(string timerId) + { + var remove = _timerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); + if (remove != null) + { + _timerProvider.Delete(remove); + } + CancellationTokenSource cancellationTokenSource; + + if (_activeRecordings.TryGetValue(timerId, out cancellationTokenSource)) + { + cancellationTokenSource.Cancel(); + } + } + + public Task CancelTimerAsync(string timerId, CancellationToken cancellationToken) + { + CancelTimerInternal(timerId); + return Task.FromResult(true); + } + + public Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) + { + var remove = _recordingProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, recordingId, StringComparison.OrdinalIgnoreCase)); + if (remove != null) + { + try + { + File.Delete(remove.Path); + } + catch (DirectoryNotFoundException) + { + + } + catch (FileNotFoundException) + { + + } + _recordingProvider.Delete(remove); + } + return Task.FromResult(true); + } + + public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken) + { + info.Id = Guid.NewGuid().ToString("N"); + _timerProvider.Add(info); + return Task.FromResult(0); + } + + public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) + { + info.Id = info.ProgramId.Substring(0, 10); + + UpdateTimersForSeriesTimer(info); + _seriesTimerProvider.Add(info); + return Task.FromResult(true); + } + + public Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) + { + _seriesTimerProvider.Update(info); + UpdateTimersForSeriesTimer(info); + return Task.FromResult(true); + } + + public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken) + { + _timerProvider.Update(info); + return Task.FromResult(true); + } + + public Task GetChannelImageAsync(string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetRecordingsAsync(CancellationToken cancellationToken) + { + return Task.FromResult((IEnumerable)_recordingProvider.GetAll()); + } + + public Task> GetTimersAsync(CancellationToken cancellationToken) + { + return Task.FromResult((IEnumerable)_timerProvider.GetAll()); + } + + public Task GetNewTimerDefaultsAsync(CancellationToken cancellationToken, ProgramInfo program = null) + { + var defaults = new SeriesTimerInfo() + { + PostPaddingSeconds = 60, + PrePaddingSeconds = 60, + RecordAnyChannel = false, + RecordAnyTime = false, + RecordNewOnly = false + }; + return Task.FromResult(defaults); + } + + public Task> GetSeriesTimersAsync(CancellationToken cancellationToken) + { + return Task.FromResult((IEnumerable)_seriesTimerProvider.GetAll()); + } + + public Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetRecordingStream(string recordingId, string streamId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task CloseLiveStream(string id, CancellationToken cancellationToken) + { + return Task.FromResult(0); + } + + public Task RecordLiveStream(string id, CancellationToken cancellationToken) + { + return Task.FromResult(0); + } + + public Task ResetTuner(string id, CancellationToken cancellationToken) + { + return Task.FromResult(0); + } + + async void _timerProvider_TimerFired(object sender, GenericEventArgs e) + { + try + { + var cancellationTokenSource = new CancellationTokenSource(); + + if (_activeRecordings.TryAdd(e.Argument.Id, cancellationTokenSource)) + { + await RecordStream(e.Argument, cancellationTokenSource.Token).ConfigureAwait(false); + } + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + _logger.ErrorException("Error recording stream", ex); + } + } + + private async Task RecordStream(TimerInfo timer, CancellationToken cancellationToken) + { + var mediaStreamInfo = await GetChannelStream(timer.ChannelId, "none", CancellationToken.None); + var duration = (timer.EndDate - RecordingHelper.GetStartTime(timer)).TotalSeconds + timer.PrePaddingSeconds; + + HttpRequestOptions httpRequestOptions = new HttpRequestOptions() + { + Url = mediaStreamInfo.Path + "?duration=" + duration + }; + + var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); + var recordPath = RecordingPath; + if (info.IsMovie) + { + recordPath = Path.Combine(recordPath, "Movies", RecordingHelper.RemoveSpecialCharacters(info.Name)); + } + else + { + recordPath = Path.Combine(recordPath, "TV", RecordingHelper.RemoveSpecialCharacters(info.Name)); + } + + recordPath = Path.Combine(recordPath, RecordingHelper.GetRecordingName(timer, info)); + Directory.CreateDirectory(Path.GetDirectoryName(recordPath)); + + var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + + if (recording == null) + { + recording = new RecordingInfo() + { + ChannelId = info.ChannelId, + Id = info.Id, + StartDate = info.StartDate, + EndDate = info.EndDate, + Genres = info.Genres ?? null, + IsKids = info.IsKids, + IsLive = info.IsLive, + IsMovie = info.IsMovie, + IsHD = info.IsHD, + IsNews = info.IsNews, + IsPremiere = info.IsPremiere, + IsSeries = info.IsSeries, + IsSports = info.IsSports, + IsRepeat = !info.IsPremiere, + Name = info.Name, + EpisodeTitle = info.EpisodeTitle ?? "", + ProgramId = info.Id, + HasImage = info.HasImage ?? false, + ImagePath = info.ImagePath ?? null, + ImageUrl = info.ImageUrl, + OriginalAirDate = info.OriginalAirDate, + Status = RecordingStatus.Scheduled, + Overview = info.Overview, + SeriesTimerId = info.Id.Substring(0, 10) + }; + _recordingProvider.Add(recording); + } + + recording.Path = recordPath; + recording.Status = RecordingStatus.InProgress; + _recordingProvider.Update(recording); + + try + { + httpRequestOptions.BufferContent = false; + httpRequestOptions.CancellationToken = cancellationToken; + _logger.Info("Writing file to path: " + recordPath); + using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET")) + { + using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + await response.Content.CopyToAsync(output, 4096, cancellationToken); + } + } + + recording.Status = RecordingStatus.Completed; + } + catch (OperationCanceledException) + { + recording.Status = RecordingStatus.Cancelled; + } + catch + { + recording.Status = RecordingStatus.Error; + } + + _recordingProvider.Update(recording); + _timerProvider.Delete(timer); + _logger.Info("Recording was a success"); + } + + private ProgramInfo GetProgramInfoFromCache(string channelId, string programId) + { + var epgData = GetEpgDataForChannel(channelId); + if (epgData.Any()) + { + return epgData.FirstOrDefault(p => p.Id == programId); + } + return null; + } + + private string RecordingPath + { + get + { + var path = GetConfiguration().RecordingPath; + + return string.IsNullOrWhiteSpace(path) + ? Path.Combine(DataPath, "recordings") + : path; + } + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + + private void UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer) + { + List epgData; + if (seriesTimer.RecordAnyChannel) + { + epgData = GetEpgDataForAllChannels(); + } + else + { + epgData = GetEpgDataForChannel(seriesTimer.ChannelId); + } + + var newTimers = RecordingHelper.GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll(), _logger); + + var existingTimers = _timerProvider.GetAll() + .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + foreach (var timer in newTimers) + { + _timerProvider.AddOrUpdate(timer); + } + + var newTimerIds = newTimers.Select(i => i.Id).ToList(); + + foreach (var timer in existingTimers) + { + if (!newTimerIds.Contains(timer.Id, StringComparer.OrdinalIgnoreCase)) + { + CancelTimerInternal(timer.Id); + } + } + } + + private string GetChannelEpgCachePath(string channelId) + { + return Path.Combine(DataPath, "epg", channelId + ".json"); + } + + private readonly object _epgLock = new object(); + private void SaveEpgDataForChannel(string channelId, List epgData) + { + var path = GetChannelEpgCachePath(channelId); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + lock (_epgLock) + { + _jsonSerializer.SerializeToFile(epgData, path); + } + } + private List GetEpgDataForChannel(string channelId) + { + try + { + lock (_epgLock) + { + return _jsonSerializer.DeserializeFromFile>(GetChannelEpgCachePath(channelId)); + } + } + catch + { + return new List(); + } + } + private List GetEpgDataForAllChannels() + { + List channelEpg = new List(); + DirectoryInfo dir = new DirectoryInfo(Path.Combine(DataPath, "epg")); + List channels = dir.GetFiles("*").Where(i => string.Equals(i.Extension, ".json", StringComparison.OrdinalIgnoreCase)).Select(f => f.Name).ToList(); + foreach (var channel in channels) + { + channelEpg.AddRange(GetEpgDataForChannel(channel)); + } + return channelEpg; + } + + public void Dispose() + { + foreach (var pair in _activeRecordings.ToList()) + { + pair.Value.Cancel(); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs new file mode 100644 index 000000000..e7feeee5a --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -0,0 +1,115 @@ +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + public class ItemDataProvider + where T : class + { + private readonly object _fileDataLock = new object(); + private List _items; + private readonly IJsonSerializer _jsonSerializer; + protected readonly ILogger Logger; + private readonly string _dataPath; + protected readonly Func EqualityComparer; + + public ItemDataProvider(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func equalityComparer) + { + Logger = logger; + _dataPath = dataPath; + EqualityComparer = equalityComparer; + _jsonSerializer = jsonSerializer; + } + + public IReadOnlyList GetAll() + { + if (_items == null) + { + lock (_fileDataLock) + { + if (_items == null) + { + _items = GetItemsFromFile(_dataPath); + } + } + } + return _items; + } + + private List GetItemsFromFile(string path) + { + var jsonFile = path + ".json"; + + try + { + return _jsonSerializer.DeserializeFromFile>(jsonFile); + } + catch (FileNotFoundException) + { + } + catch (DirectoryNotFoundException ex) + { + } + catch (IOException ex) + { + Logger.ErrorException("Error deserializing {0}", ex, jsonFile); + throw; + } + catch (Exception ex) + { + Logger.ErrorException("Error deserializing {0}", ex, jsonFile); + } + return new List(); + } + + private void UpdateList(List newList) + { + lock (_fileDataLock) + { + _jsonSerializer.SerializeToFile(newList, _dataPath + ".json"); + _items = newList; + } + } + + public virtual void Update(T item) + { + var list = GetAll().ToList(); + + var index = list.FindIndex(i => EqualityComparer(i, item)); + + if (index == -1) + { + throw new ArgumentException("item not found"); + } + + list[index] = item; + + UpdateList(list); + } + + public virtual void Add(T item) + { + var list = GetAll().ToList(); + + if (list.Any(i => EqualityComparer(i, item))) + { + throw new ArgumentException("item already exists"); + } + + list.Add(item); + + UpdateList(list); + } + + public virtual void Delete(T item) + { + var list = GetAll().Where(i => !EqualityComparer(i, item)).ToList(); + + UpdateList(list); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs new file mode 100644 index 000000000..0aa1cb244 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -0,0 +1,119 @@ +using System.Text; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + internal class RecordingHelper + { + public static List GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable epgData, IReadOnlyList currentRecordings, ILogger logger) + { + List timers = new List(); + + // Filtered Per Show + var filteredEpg = epgData.Where(epg => epg.Id.Substring(0, 10) == seriesTimer.Id); + + if (!seriesTimer.RecordAnyTime) + { + filteredEpg = filteredEpg.Where(epg => (seriesTimer.StartDate.TimeOfDay == epg.StartDate.TimeOfDay)); + } + + if (seriesTimer.RecordNewOnly) + { + filteredEpg = filteredEpg.Where(epg => !epg.IsRepeat); //Filtered by New only + } + + if (!seriesTimer.RecordAnyChannel) + { + filteredEpg = filteredEpg.Where(epg => string.Equals(epg.ChannelId, seriesTimer.ChannelId, StringComparison.OrdinalIgnoreCase)); + } + + filteredEpg = filteredEpg.Where(epg => seriesTimer.Days.Contains(epg.StartDate.DayOfWeek)); + + filteredEpg = filteredEpg.Where(epg => currentRecordings.All(r => r.Id.Substring(0, 14) != epg.Id.Substring(0, 14))); //filtered recordings already running + + filteredEpg = filteredEpg.GroupBy(epg => epg.Id.Substring(0, 14)).Select(g => g.First()).ToList(); + + foreach (var epg in filteredEpg) + { + timers.Add(CreateTimer(epg, seriesTimer)); + } + + return timers; + } + + public static DateTime GetStartTime(TimerInfo timer) + { + if (timer.StartDate.AddSeconds(-timer.PrePaddingSeconds + 1) < DateTime.UtcNow) + { + return DateTime.UtcNow.AddSeconds(1); + } + return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds); + } + + public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo series) + { + var timer = new TimerInfo(); + + timer.ChannelId = parent.ChannelId; + timer.Id = (series.Id + parent.Id).GetMD5().ToString("N"); + timer.StartDate = parent.StartDate; + timer.EndDate = parent.EndDate; + timer.ProgramId = parent.Id; + timer.PrePaddingSeconds = series.PrePaddingSeconds; + timer.PostPaddingSeconds = series.PostPaddingSeconds; + timer.IsPostPaddingRequired = series.IsPostPaddingRequired; + timer.IsPrePaddingRequired = series.IsPrePaddingRequired; + timer.Priority = series.Priority; + timer.Name = parent.Name; + timer.Overview = parent.Overview; + timer.SeriesTimerId = series.Id; + + return timer; + } + + public static string GetRecordingName(TimerInfo timer, ProgramInfo info) + { + if (info == null) + { + return (timer.ProgramId + ".ts"); + } + var fancyName = info.Name; + if (info.ProductionYear != null) + { + fancyName += "_(" + info.ProductionYear + ")"; + } + if (info.IsSeries) + { + fancyName += "_" + info.EpisodeTitle.Replace("Season: ", "S").Replace(" Episode: ", "E"); + } + if (info.IsHD ?? false) + { + fancyName += "_HD"; + } + if (info.OriginalAirDate != null) + { + fancyName += "_" + info.OriginalAirDate.Value.ToString("yyyy-MM-dd"); + } + return RemoveSpecialCharacters(fancyName) + ".ts"; + } + + public static string RemoveSpecialCharacters(string str) + { + StringBuilder sb = new StringBuilder(); + foreach (char c in str) + { + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_' || c == '-' || c == ' ') + { + sb.Append(c); + } + } + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs new file mode 100644 index 000000000..eab278eb4 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs @@ -0,0 +1,25 @@ +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using System; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + public class SeriesTimerManager : ItemDataProvider + { + public SeriesTimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath) + : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) + { + } + + public override void Add(SeriesTimerInfo item) + { + if (string.IsNullOrWhiteSpace(item.Id)) + { + throw new ArgumentException("SeriesTimerInfo.Id cannot be null or empty."); + } + + base.Add(item); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs new file mode 100644 index 000000000..323197aa5 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -0,0 +1,114 @@ +using MediaBrowser.Common.Events; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Events; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + public class TimerManager : ItemDataProvider + { + private readonly ConcurrentDictionary _timers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + public event EventHandler> TimerFired; + + public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath) + : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)) + { + } + + public void RestartTimers() + { + StopTimers(); + } + + public void StopTimers() + { + foreach (var pair in _timers.ToList()) + { + pair.Value.Dispose(); + } + + _timers.Clear(); + } + + public override void Delete(TimerInfo item) + { + base.Delete(item); + + Timer timer; + if (_timers.TryRemove(item.Id, out timer)) + { + timer.Dispose(); + } + } + + public override void Update(TimerInfo item) + { + base.Update(item); + + Timer timer; + if (_timers.TryGetValue(item.Id, out timer)) + { + var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow; + timer.Change(timespan, TimeSpan.Zero); + } + else + { + AddTimer(item); + } + } + + public override void Add(TimerInfo item) + { + if (string.IsNullOrWhiteSpace(item.Id)) + { + throw new ArgumentException("TimerInfo.Id cannot be null or empty."); + } + + base.Add(item); + AddTimer(item); + } + + public void AddOrUpdate(TimerInfo item) + { + var list = GetAll().ToList(); + + if (!list.Any(i => EqualityComparer(i, item))) + { + Add(item); + } + else + { + Update(item); + } + } + + private void AddTimer(TimerInfo item) + { + var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow; + + var timer = new Timer(TimerCallback, item.Id, timespan, TimeSpan.Zero); + + if (!_timers.TryAdd(item.Id, timer)) + { + timer.Dispose(); + } + } + + private void TimerCallback(object state) + { + var timerId = (string)state; + + var timer = GetAll().FirstOrDefault(i => string.Equals(i.Id, timerId, StringComparison.OrdinalIgnoreCase)); + if (timer != null) + { + EventHelper.FireEventIfNotNull(TimerFired, this, new GenericEventArgs { Argument = timer }, Logger); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 9fef0560d..80ec2a036 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1); - private ConcurrentDictionary _refreshedPrograms = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _refreshedPrograms = new ConcurrentDictionary(); public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs new file mode 100644 index 000000000..cadbe7bc3 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs @@ -0,0 +1,205 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts +{ + public class HdHomerun : ITunerHost + { + private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + private readonly IJsonSerializer _jsonSerializer; + private readonly IConfigurationManager _config; + + public HdHomerun(IHttpClient httpClient, ILogger logger, IJsonSerializer jsonSerializer, IConfigurationManager config) + { + _httpClient = httpClient; + _logger = logger; + _jsonSerializer = jsonSerializer; + _config = config; + } + + public string Name + { + get { return "HD Homerun"; } + } + + public string Type + { + get { return "hdhomerun"; } + } + + public async Task> GetChannels(TunerHostInfo info, CancellationToken cancellationToken) + { + var options = new HttpRequestOptions + { + Url = string.Format("{0}/lineup.json", GetApiUrl(info)), + CancellationToken = cancellationToken + }; + using (var stream = await _httpClient.Get(options)) + { + var root = _jsonSerializer.DeserializeFromStream>(stream); + + if (root != null) + { + return root.Select(i => new ChannelInfo + { + Name = i.GuideName, + Number = i.GuideNumber.ToString(CultureInfo.InvariantCulture), + Id = i.GuideNumber.ToString(CultureInfo.InvariantCulture), + IsFavorite = i.Favorite + + }); + } + return new List(); + } + } + + public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + { + var httpOptions = new HttpRequestOptions() + { + Url = string.Format("{0}/tuners.html", GetApiUrl(info)), + CancellationToken = cancellationToken + }; + using (var stream = await _httpClient.Get(httpOptions)) + { + var tuners = new List(); + using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) + { + while (!sr.EndOfStream) + { + string line = StripXML(sr.ReadLine()); + if (line.Contains("Channel")) + { + LiveTvTunerStatus status; + var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase); + var name = line.Substring(0, index - 1); + var currentChannel = line.Substring(index + 7); + if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; } + tuners.Add(new LiveTvTunerInfo() + { + Name = name, + SourceType = Name, + ProgramName = currentChannel, + Status = status + }); + } + } + } + return tuners; + } + } + + public string GetApiUrl(TunerHostInfo info) + { + var url = info.Url; + + if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + url = "http://" + url; + } + + return url.TrimEnd('/'); + } + + private static string StripXML(string source) + { + char[] buffer = new char[source.Length]; + int bufferIndex = 0; + bool inside = false; + + for (int i = 0; i < source.Length; i++) + { + char let = source[i]; + if (let == '<') + { + inside = true; + continue; + } + if (let == '>') + { + inside = false; + continue; + } + if (!inside) + { + buffer[bufferIndex] = let; + bufferIndex++; + } + } + return new string(buffer, 0, bufferIndex); + } + + private class Channels + { + public string GuideNumber { get; set; } + public string GuideName { get; set; } + public string URL { get; set; } + public bool Favorite { get; set; } + public bool DRM { get; set; } + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + + public List GetTunerHosts() + { + return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); + } + + public async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + { + var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); + var tuners = await GetTunerInfos(info, cancellationToken).ConfigureAwait(false); + + var channel = channels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase)); + if (channel != null) + { + if (tuners.FindIndex(t => t.Status == LiveTvTunerStatus.Available) >= 0) + { + return new MediaSourceInfo + { + Path = GetApiUrl(info) + "/auto/v" + channelId, + Protocol = MediaProtocol.Http, + MediaStreams = new List + { + new MediaStream + { + 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 + }, + 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 + + } + } + }; + } + + throw new ApplicationException("No tuners avaliable."); + } + throw new ApplicationException("Channel not found."); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs new file mode 100644 index 000000000..615e07a82 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -0,0 +1,189 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.MediaInfo; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts +{ + public class M3UTunerHost : ITunerHost + { + public string Type + { + get { return "m3u"; } + } + + public string Name + { + get { return "M3U Tuner"; } + } + + private readonly IConfigurationManager _config; + + public M3UTunerHost(IConfigurationManager config) + { + _config = config; + } + + public Task> GetChannels(TunerHostInfo info, CancellationToken cancellationToken) + { + int position = 0; + string line; + // Read the file and display it line by line. + var file = new StreamReader(info.Url); + var channels = new List(); + while ((line = file.ReadLine()) != null) + { + line = line.Trim(); + if (!String.IsNullOrWhiteSpace(line)) + { + if (position == 0 && !line.StartsWith("#EXTM3U")) + { + throw new ApplicationException("wrong file"); + } + if (position % 2 == 0) + { + if (position != 0) + { + channels.Last().Path = line; + } + else + { + line = line.Replace("#EXTM3U", ""); + line = line.Trim(); + var vars = line.Split(' ').ToList(); + foreach (var variable in vars) + { + var list = variable.Replace('"', ' ').Split('='); + switch (list[0]) + { + case ("id"): + //_id = list[1]; + break; + } + } + } + } + else + { + if (!line.StartsWith("#EXTINF:")) { throw new ApplicationException("Bad file"); } + line = line.Replace("#EXTINF:", ""); + var nameStart = line.LastIndexOf(','); + line = line.Substring(0, nameStart); + var vars = line.Split(' ').ToList(); + vars.RemoveAt(0); + channels.Add(new M3UChannel()); + foreach (var variable in vars) + { + var list = variable.Replace('"', ' ').Split('='); + switch (list[0]) + { + case "tvg-id": + channels.Last().Id = list[1]; + channels.Last().Number = list[1]; + break; + case "tvg-name": + channels.Last().Name = list[1]; + break; + } + } + } + position++; + } + } + file.Close(); + return Task.FromResult((IEnumerable)channels); + } + + public Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + { + var list = new List(); + + list.Add(new LiveTvTunerInfo() + { + Name = Name, + SourceType = Type, + Status = LiveTvTunerStatus.Available, + Id = info.Url.GetMD5().ToString("N"), + Url = info.Url + }); + + return Task.FromResult(list); + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + + public List GetTunerHosts() + { + return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); + } + + public async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + { + var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); + var m3uchannels = channels.Cast(); + var channel = m3uchannels.FirstOrDefault(c => c.Id == channelId); + if (channel != null) + { + var path = channel.Path; + MediaProtocol protocol = MediaProtocol.File; + if (path.StartsWith("http")) + { + protocol = MediaProtocol.Http; + } + else if (path.StartsWith("rtmp")) + { + protocol = MediaProtocol.Rtmp; + } + else if (path.StartsWith("rtsp")) + { + protocol = MediaProtocol.Rtsp; + } + + return new MediaSourceInfo + { + Path = channel.Path, + Protocol = protocol, + MediaStreams = new List + { + new MediaStream + { + 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 + }, + 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 + + } + } + }; + } + throw new ApplicationException("Host doesnt provide this channel"); + } + + class M3UChannel : ChannelInfo + { + public string Path { get; set; } + + public M3UChannel() + { + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 33b2493f5..bc1d07426 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -216,10 +216,17 @@ + + + + + + + -- cgit v1.2.3 From 9457ff7ce87e4752a7f51381b309604ee08f030e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 21 Jul 2015 00:22:46 -0400 Subject: completed tuner hosts --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 49 +++++++++++++++++++++- .../LiveTv/IListingsProvider.cs | 7 +++- .../LiveTv/LiveTvServiceStatusInfo.cs | 8 +++- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs | 5 +++ .../LiveTv/EmbyTV/EmbyTV.cs | 4 ++ .../LiveTv/Listings/SchedulesDirect.cs | 16 +++++++ .../LiveTv/LiveTvManager.cs | 1 + .../LiveTv/TunerHosts/HdHomerun.cs | 29 +++++++++++-- .../Localization/JavaScript/javascript.json | 3 +- .../Localization/Server/server.json | 9 +++- .../MediaBrowser.Server.Implementations.csproj | 1 + 12 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index c474642d5..49ba001ce 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Dto; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Net; @@ -330,15 +331,31 @@ namespace MediaBrowser.Api.LiveTv public string UserId { get; set; } } + [Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")] + [Authenticated] + public class AddTunerHost : TunerHostInfo, IReturnVoid + { + } + + [Route("/LiveTv/TunerHosts", "DELETE", Summary = "Deletes a tuner host")] + [Authenticated] + public class DeleteTunerHost : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Tuner host id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")] + public string Id { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; private readonly IUserManager _userManager; + private readonly IConfigurationManager _config; - public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager) + public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config) { _liveTvManager = liveTvManager; _userManager = userManager; + _config = config; } private void AssertUserCanManageLiveTv() @@ -356,6 +373,34 @@ namespace MediaBrowser.Api.LiveTv } } + public void Post(AddTunerHost request) + { + var config = GetConfiguration(); + + config.TunerHosts.Add(new TunerHostInfo + { + Id = Guid.NewGuid().ToString("N"), + Url = request.Url, + Type = request.Type + }); + + _config.SaveConfiguration("livetv", config); + } + + public void Delete(DeleteTunerHost request) + { + var config = GetConfiguration(); + + config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); + + _config.SaveConfiguration("livetv", config); + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + public async Task Get(GetLiveTvInfo request) { var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 2cef455e8..75ca7e0dc 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,7 +1,12 @@ - +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + namespace MediaBrowser.Controller.LiveTv { public interface IListingsProvider { + Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs index 0cb064aba..4da238acf 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs @@ -34,10 +34,16 @@ namespace MediaBrowser.Controller.LiveTv /// /// The tuners. public List Tuners { get; set; } - + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// true if this instance is visible; otherwise, false. + public bool IsVisible { get; set; } + public LiveTvServiceStatusInfo() { Tuners = new List(); + IsVisible = true; } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 303b12af7..2ca7397c1 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -18,6 +18,7 @@ namespace MediaBrowser.Model.LiveTv public class TunerHostInfo { + public string Id { get; set; } public string Url { get; set; } public string Type { get; set; } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs index 264870ffb..25d3b289f 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs @@ -42,6 +42,11 @@ namespace MediaBrowser.Model.LiveTv /// /// true if this instance has update available; otherwise, false. public bool HasUpdateAvailable { get; set; } + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// true if this instance is visible; otherwise, false. + public bool IsVisible { get; set; } public List Tuners { get; set; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index d0a271260..b71d62f43 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -20,6 +20,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { public class EmbyTV : ILiveTvService, IDisposable { + private readonly IApplicationHost _appHpst; private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly IConfigurationManager _config; @@ -32,6 +33,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) { + _appHpst = appHost; _logger = logger; _httpClient = httpClient; _config = config; @@ -90,6 +92,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV status.Tuners = list; status.Status = LiveTvServiceStatus.Ok; + status.Version = _appHpst.ApplicationVersion.ToString(); + status.IsVisible = false; return status; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs new file mode 100644 index 000000000..7070c5a5f --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -0,0 +1,16 @@ +using MediaBrowser.Controller.LiveTv; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.Listings +{ + public class SchedulesDirect : IListingsProvider + { + public Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 80ec2a036..05bc276b8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2057,6 +2057,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Version = statusInfo.Version; info.HasUpdateAvailable = statusInfo.HasUpdateAvailable; info.HomePageUrl = service.HomePageUrl; + info.IsVisible = statusInfo.IsVisible; info.Tuners = statusInfo.Tuners.Select(i => { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs index cadbe7bc3..b5b588682 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -14,6 +15,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { @@ -70,12 +72,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { - var httpOptions = new HttpRequestOptions() + string model = null; + + using (var stream = await _httpClient.Get(new HttpRequestOptions() + { + Url = string.Format("{0}/", GetApiUrl(info)), + CancellationToken = cancellationToken + })) + { + using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) + { + while (!sr.EndOfStream) + { + string line = StripXML(sr.ReadLine()); + if (line.StartsWith("Model:")) { model = line.Replace("Model: ", ""); } + //if (line.StartsWith("Device ID:")) { deviceID = line.Replace("Device ID: ", ""); } + //if (line.StartsWith("Firmware:")) { firmware = line.Replace("Firmware: ", ""); } + } + } + } + + using (var stream = await _httpClient.Get(new HttpRequestOptions() { Url = string.Format("{0}/tuners.html", GetApiUrl(info)), CancellationToken = cancellationToken - }; - using (var stream = await _httpClient.Get(httpOptions)) + })) { var tuners = new List(); using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) @@ -93,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts tuners.Add(new LiveTvTunerInfo() { Name = name, - SourceType = Name, + SourceType = string.IsNullOrWhiteSpace(model) ? Name : model, ProgramName = currentChannel, Status = status }); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 2d56e9656..89ff3a984 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -816,5 +816,6 @@ "ButtonShareHelp": "Share a web page containing media information with social media. Media files are never shared publicly.", "ButtonShare": "Share", "HeaderConfirm": "Confirm", - "ButtonAdvancedRefresh": "Advanced Refresh" + "ButtonAdvancedRefresh": "Advanced Refresh", + "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 5a1d9f29e..b6c1321fa 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1473,5 +1473,12 @@ "HeaderShortOverview": "Short Overview", "HeaderType": "Type", "HeaderSeverity": "Severity", - "OptionReportActivities": "Activities Log" + "OptionReportActivities": "Activities Log", + "HeaderTunerDevices": "Tuner Devices", + "ButtonAddDevice": "Add Device", + "HeaderAddDevice": "Add Device", + "HeaderExternalServices": "External Services", + "LabelIpAddressPath": "IP Address / Path:", + "TabExternalServices": "External Services", + "TabTuners": "Tuners" } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index bc1d07426..dc149318b 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -221,6 +221,7 @@ + -- cgit v1.2.3 From 7300a475d1892c553bb0a3a5fc21cc32d09b4950 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 23 Jul 2015 01:25:55 -0400 Subject: update live tv setup --- .../HttpClientManager/HttpClientManager.cs | 3 + .../LiveTv/IListingsProvider.cs | 7 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 14 +- .../Channels/ChannelDownloadScheduledTask.cs | 8 +- .../Channels/ChannelManager.cs | 93 +-- .../EntryPoints/UsageReporter.cs | 2 + .../LiveTv/EmbyTV/EmbyTV.cs | 51 +- .../LiveTv/Listings/SchedulesDirect.cs | 836 ++++++++++++++++++++- .../Localization/JavaScript/javascript.json | 5 +- .../Localization/Server/server.json | 7 +- .../MediaBrowser.WebDashboard.csproj | 6 + 11 files changed, 923 insertions(+), 109 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 7ca6f43d6..18441161f 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -68,6 +68,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c ServicePointManager.Expect100Continue = false; + + // Trakt requests sometimes fail without this + ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls; } /// diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 75ca7e0dc..beaa4eeaf 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,4 +1,5 @@ -using System; +using MediaBrowser.Model.LiveTv; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -7,6 +8,8 @@ namespace MediaBrowser.Controller.LiveTv { public interface IListingsProvider { - Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + string Name { get; } + Task> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 2ca7397c1..c78fbe630 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -6,13 +6,16 @@ namespace MediaBrowser.Model.LiveTv { public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } - public List TunerHosts { get; set; } public string RecordingPath { get; set; } + public List TunerHosts { get; set; } + public List ListingProviders { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; TunerHosts = new List(); + ListingProviders = new List(); } } @@ -22,4 +25,13 @@ namespace MediaBrowser.Model.LiveTv public string Url { get; set; } public string Type { get; set; } } + + public class ListingsProviderInfo + { + public string ProviderName { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string ZipCode { get; set; } + public string ListingsId { get; set; } + } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index 18711c61e..337e26e8d 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -1,8 +1,6 @@ using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Security; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -29,22 +27,18 @@ namespace MediaBrowser.Server.Implementations.Channels private readonly IChannelManager _manager; private readonly IServerConfigurationManager _config; private readonly ILogger _logger; - private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; - private readonly ISecurityManager _security; - public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem, ILibraryManager libraryManager, IUserManager userManager, ISecurityManager security) + public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IUserManager userManager) { _manager = manager; _config = config; _logger = logger; - _httpClient = httpClient; _fileSystem = fileSystem; _libraryManager = libraryManager; _userManager = userManager; - _security = security; } public string Name diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 0cd4b0a5c..3e58e3bd5 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -255,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.Channels sources.InsertRange(0, cachedVersions); } - return sources.Where(IsValidMediaSource); + return sources; } public async Task> GetDynamicMediaSources(IChannelMediaItem item, CancellationToken cancellationToken) @@ -279,7 +278,6 @@ namespace MediaBrowser.Server.Implementations.Channels var list = SortMediaInfoResults(results) .Select(i => GetMediaSource(item, i)) - .Where(IsValidMediaSource) .ToList(); var cachedVersions = GetCachedChannelItemMediaSources(item); @@ -1424,18 +1422,8 @@ namespace MediaBrowser.Server.Implementations.Channels foreach (var source in list) { - try - { - await TryDownloadChannelItem(source, item, destination, progress, cancellationToken).ConfigureAwait(false); - return; - } - catch (HttpException ex) - { - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) - { - MarkBadMediaSource(source); - } - } + await TryDownloadChannelItem(source, item, destination, progress, cancellationToken).ConfigureAwait(false); + return; } } @@ -1525,81 +1513,6 @@ namespace MediaBrowser.Server.Implementations.Channels } } - private readonly ReaderWriterLockSlim _mediaSourceHistoryLock = new ReaderWriterLockSlim(); - private bool IsValidMediaSource(MediaSourceInfo source) - { - if (source.Protocol == MediaProtocol.Http) - { - return !GetBadMediaSourceHistory().Contains(source.Path, StringComparer.OrdinalIgnoreCase); - } - return true; - } - - private void MarkBadMediaSource(MediaSourceInfo source) - { - var list = GetBadMediaSourceHistory(); - list.Add(source.Path); - - var path = GetMediaSourceHistoryPath(); - - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - if (_mediaSourceHistoryLock.TryEnterWriteLock(TimeSpan.FromSeconds(5))) - { - try - { - File.WriteAllLines(path, list.ToArray(), Encoding.UTF8); - } - catch (Exception ex) - { - _logger.ErrorException("Error saving file", ex); - } - finally - { - _mediaSourceHistoryLock.ExitWriteLock(); - } - } - } - - private ConcurrentBag _badMediaSources = null; - private ConcurrentBag GetBadMediaSourceHistory() - { - if (_badMediaSources == null) - { - var path = GetMediaSourceHistoryPath(); - - if (_mediaSourceHistoryLock.TryEnterReadLock(TimeSpan.FromSeconds(1))) - { - if (_badMediaSources == null) - { - try - { - _badMediaSources = new ConcurrentBag(File.ReadAllLines(path, Encoding.UTF8)); - } - catch (IOException) - { - _badMediaSources = new ConcurrentBag(); - } - catch (Exception ex) - { - _logger.ErrorException("Error reading file", ex); - _badMediaSources = new ConcurrentBag(); - } - finally - { - _mediaSourceHistoryLock.ExitReadLock(); - } - } - } - } - return _badMediaSources; - } - - private string GetMediaSourceHistoryPath() - { - return Path.Combine(_config.ApplicationPaths.DataPath, "channels", "failures.txt"); - } - private void IncrementDownloadCount(string key, int? limit) { if (!limit.HasValue) diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs index 315493e0d..77dd54a80 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs @@ -46,6 +46,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints data["guests"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest).ToString(CultureInfo.InvariantCulture); data["linkedusers"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.LinkedUser).ToString(CultureInfo.InvariantCulture); + data["plugins"] = string.Join(",", _applicationHost.Plugins.Select(i => i.Id).ToArray()); + return _httpClient.Post(MbAdminUrl + "service/registration/ping", data, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index b71d62f43..26e070921 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -26,11 +26,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; - private readonly List _tunerHosts = new List(); private readonly ItemDataProvider _recordingProvider; private readonly ItemDataProvider _seriesTimerProvider; private readonly TimerManager _timerProvider; + private readonly List _tunerHosts = new List(); + private readonly List _listingProviders = new List(); + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) { _appHpst = appHost; @@ -39,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _config = config; _jsonSerializer = jsonSerializer; _tunerHosts.AddRange(appHost.GetExports()); + _listingProviders.AddRange(appHost.GetExports()); _recordingProvider = new ItemDataProvider(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); @@ -118,6 +121,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } + if (list.Count > 0) + { + foreach (var provider in GetListingProviders()) + { + await provider.Item1.AddMetadata(provider.Item2, list, cancellationToken).ConfigureAwait(false); + } + } + return list; } @@ -246,9 +257,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult((IEnumerable)_seriesTimerProvider.GetAll()); } - public Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + public async Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var allChannels = await GetChannelsAsync(cancellationToken).ConfigureAwait(false); + var channelInfo = allChannels.FirstOrDefault(i => string.Equals(channelId, i.Id, StringComparison.OrdinalIgnoreCase)); + + if (channelInfo == null) + { + _logger.Debug("Returning empty program list because channel was not found."); + return new List(); + } + + foreach (var provider in GetListingProviders()) + { + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelInfo, startDateUtc, endDateUtc, cancellationToken) + .ConfigureAwait(false); + var list = programs.ToList(); + + if (list.Count > 0) + { + return list; + } + } + + return new List(); + } + + private List> GetListingProviders() + { + return GetConfiguration().ListingProviders + .Select(i => + { + var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase)); + + return provider == null ? null : new Tuple(provider, i); + }) + .Where(i => i != null) + .ToList(); } public Task GetRecordingStream(string recordingId, string streamId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 7070c5a5f..3b7564983 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -1,6 +1,15 @@ -using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -8,9 +17,830 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { public class SchedulesDirect : IListingsProvider { - public Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + private readonly ILogger _logger; + private readonly IJsonSerializer _jsonSerializer; + private readonly IHttpClient _httpClient; + private const string UserAgent = "EmbyTV"; + private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); + + private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; + + private readonly ConcurrentDictionary _channelPair = + new ConcurrentDictionary(); + + public SchedulesDirect(ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient) + { + _logger = logger; + _jsonSerializer = jsonSerializer; + _httpClient = httpClient; + } + + public async Task> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + var channelNumber = channel.Number; + + List programsInfo = new List(); + + var token = await GetToken(info, cancellationToken); + + if (string.IsNullOrWhiteSpace(token)) + { + return programsInfo; + } + + if (string.IsNullOrWhiteSpace(info.ListingsId)) + { + return programsInfo; + } + + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/schedules", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + List dates = new List(); + int numberOfDay = 0; + DateTime lastEntry = startDateUtc; + while (lastEntry != endDateUtc) + { + lastEntry = startDateUtc.AddDays(numberOfDay); + dates.Add(lastEntry.ToString("yyyy-MM-dd")); + numberOfDay++; + } + + ScheduleDirect.Station station = null; + + if (!_channelPair.TryGetValue("", out station)) + { + return programsInfo; + } + string stationID = station.stationID; + + _logger.Info("Channel Station ID is: " + stationID); + List requestList = + new List() + { + new ScheduleDirect.RequestScheduleForChannel() + { + stationID = stationID, + date = dates + } + }; + + var requestString = _jsonSerializer.SerializeToString(requestList); + _logger.Debug("Request string for schedules is: " + requestString); + httpOptions.RequestContent = requestString; + using (var response = await _httpClient.Post(httpOptions)) + { + StreamReader reader = new StreamReader(response.Content); + string responseString = reader.ReadToEnd(); + var dailySchedules = _jsonSerializer.DeserializeFromString>(responseString); + _logger.Debug("Found " + dailySchedules.Count() + " programs on " + channelNumber + + " ScheduleDirect"); + + httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/programs", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + List programsID = new List(); + programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList(); + var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]"; + httpOptions.RequestContent = requestBody; + + using (var innerResponse = await _httpClient.Post(httpOptions)) + { + StreamReader innerReader = new StreamReader(innerResponse.Content); + responseString = innerReader.ReadToEnd(); + var programDetails = + _jsonSerializer.DeserializeFromString>( + responseString); + var programDict = programDetails.ToDictionary(p => p.programID, y => y); + + var images = await GetImageForPrograms(programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken); + + var schedules = dailySchedules.SelectMany(d => d.programs); + foreach (ScheduleDirect.Program schedule in schedules) + { + _logger.Debug("Proccesing Schedule for statio ID " + stationID + + " which corresponds to channel " + channelNumber + " and program id " + + schedule.programID + " which says it has images? " + + programDict[schedule.programID].hasImageArtwork); + + var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10)); + if (imageIndex > -1) + { + programDict[schedule.programID].images = GetProgramLogo(ApiUrl, images[imageIndex]); + } + + programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID])); + } + _logger.Info("Finished with EPGData"); + } + } + + return programsInfo; + } + + public async Task AddMetadata(ListingsProviderInfo info, List channels, + CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + _channelPair.Clear(); + + if (!String.IsNullOrWhiteSpace(token) && !String.IsNullOrWhiteSpace(info.ListingsId)) + { + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups/" + info.ListingsId, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + using (var response = await _httpClient.Get(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(response); + _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); + _logger.Info("Mapping Stations to Channel"); + foreach (ScheduleDirect.Map map in root.map) + { + var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); + _logger.Debug("Found channel: " + channel + " in Schedules Direct"); + var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); + + if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) + { + _channelPair.TryAdd(channel, schChannel); + } + } + _logger.Info("Added " + _channelPair.Count() + " channels to the dictionary"); + + foreach (ChannelInfo channel in channels) + { + // Helper.logger.Info("Modifyin channel " + channel.Number); + if (_channelPair.ContainsKey(channel.Number)) + { + string channelName; + if (_channelPair[channel.Number].logo != null) + { + channel.ImageUrl = _channelPair[channel.Number].logo.URL; + channel.HasImage = true; + } + if (_channelPair[channel.Number].affiliate != null) + { + channelName = _channelPair[channel.Number].affiliate; + } + else + { + channelName = _channelPair[channel.Number].name; + } + channel.Name = channelName; + } + else + { + _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + + channel.Name); + } + } + } + } + } + + private async Task GetLineup(string listingsId, string token, CancellationToken cancellationToken) + { + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups/" + listingsId, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + using (var response = await _httpClient.Get(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(response); + _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); + _logger.Info("Mapping Stations to Channel"); + foreach (ScheduleDirect.Map map in root.map) + { + var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); + _logger.Debug("Found channel: " + channel + " in Schedules Direct"); + + var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); + + if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) + { + _channelPair.TryAdd(channel, schChannel); + } + } + + return root; + } + } + + private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, + ScheduleDirect.ProgramDetails details) + { + _logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); + DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", + CultureInfo.InvariantCulture); + DateTime endAt = startAt.AddSeconds(programInfo.duration); + ProgramAudio audioType = ProgramAudio.Stereo; + bool hdtv = false; + bool repeat = (programInfo.@new == null); + string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channel; + + + if (programInfo.audioProperties != null) + { + if (programInfo.audioProperties.Exists(item => item == "stereo")) + { + audioType = ProgramAudio.Stereo; + } + else + { + audioType = ProgramAudio.Mono; + } + } + + if ((programInfo.videoProperties != null)) + { + hdtv = programInfo.videoProperties.Exists(item => item == "hdtv"); + } + + string desc = ""; + if (details.descriptions != null) + { + if (details.descriptions.description1000 != null) + { + desc = details.descriptions.description1000[0].description; + } + else if (details.descriptions.description100 != null) + { + desc = details.descriptions.description100[0].description; + } + } + ScheduleDirect.Gracenote gracenote; + string EpisodeTitle = ""; + if (details.metadata != null) + { + gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; + if ((details.showType ?? "No ShowType") == "Series") + { + EpisodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; + } + } + if (details.episodeTitle150 != null) + { + EpisodeTitle = EpisodeTitle + " " + details.episodeTitle150; + } + bool hasImage = false; + var imageLink = ""; + + if (details.hasImageArtwork) + { + imageLink = details.images; + } + + + var info = new ProgramInfo + { + ChannelId = channel, + Id = newID, + Overview = desc, + StartDate = startAt, + EndDate = endAt, + Genres = new List() { "N/A" }, + Name = details.titles[0].title120 ?? "Unkown", + OfficialRating = "0", + CommunityRating = null, + EpisodeTitle = EpisodeTitle, + Audio = audioType, + IsHD = hdtv, + IsRepeat = repeat, + IsSeries = + ((details.showType ?? "No ShowType") == "Series") || + (details.showType ?? "No ShowType") == "Miniseries", + ImageUrl = imageLink, + HasImage = details.hasImageArtwork, + IsNews = false, + IsKids = false, + IsSports = + ((details.showType ?? "No ShowType") == "Sports non-event") || + (details.showType ?? "No ShowType") == "Sports event", + IsLive = false, + IsMovie = + (details.showType ?? "No ShowType") == "Feature Film" || + (details.showType ?? "No ShowType") == "TV Movie" || + (details.showType ?? "No ShowType") == "Short Film", + IsPremiere = false, + }; + //logger.Info("Done init"); + if (null != details.originalAirDate) + { + info.OriginalAirDate = DateTime.Parse(details.originalAirDate); + } + + if (details.genres != null) + { + info.Genres = details.genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); + info.IsNews = details.genres.Contains("news", StringComparer.OrdinalIgnoreCase); + info.IsKids = false; + } + return info; + } + + private string GetProgramLogo(string apiUrl, ScheduleDirect.ShowImages images) + { + string url = ""; + if (images.data != null) + { + var smallImages = images.data.Where(i => i.size == "Sm").ToList(); + if (smallImages.Any()) + { + images.data = smallImages; + } + var logoIndex = images.data.FindIndex(i => i.category == "Logo"); + if (logoIndex == -1) + { + logoIndex = 0; + } + if (images.data[logoIndex].uri.Contains("http")) + { + url = images.data[logoIndex].uri; + } + else + { + url = apiUrl + "/image/" + images.data[logoIndex].uri; + } + _logger.Debug("URL for image is : " + url); + } + return url; + } + + private async Task> GetImageForPrograms(List programIds, + CancellationToken cancellationToken) + { + var imageIdString = "["; + + programIds.ForEach(i => + { + if (!imageIdString.Contains(i.Substring(0, 10))) + { + imageIdString += "\"" + i.Substring(0, 10) + "\","; + } + ; + }); + imageIdString = imageIdString.TrimEnd(',') + "]"; + _logger.Debug("Json for show images = " + imageIdString); + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/metadata/programs", + UserAgent = UserAgent, + CancellationToken = cancellationToken, + RequestContent = imageIdString + }; + List images; + using (var innerResponse2 = await _httpClient.Post(httpOptions)) + { + images = _jsonSerializer.DeserializeFromStream>( + innerResponse2.Content); + } + + return images; + } + + public async Task> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + var lineups = new List(); + + if (string.IsNullOrWhiteSpace(token)) + { + return lineups; + } + + _logger.Info("Headends on account "); + + var options = new HttpRequestOptions() + { + Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + options.RequestHeaders["token"] = token; + + try + { + using (Stream responce = await _httpClient.Get(options).ConfigureAwait(false)) + { + var root = _jsonSerializer.DeserializeFromStream>(responce); + _logger.Info("Lineups on account "); + if (root != null) + { + foreach (ScheduleDirect.Headends headend in root) + { + _logger.Info("Headend: " + headend.headend); + foreach (ScheduleDirect.Lineup lineup in headend.lineups) + { + _logger.Info("Headend: " + lineup.uri.Substring(18)); + lineups.Add(new NameIdPair() + { + Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, + Id = lineup.uri.Substring(18) + }); + } + } + } + else + { + _logger.Info("No lineups on account"); + } + } + } + catch (Exception ex) + { + _logger.Error("Error getting headends", ex); + } + + return lineups; + } + + private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); + + private async Task GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) + { + await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + var username = info.Username; + + // Reset the token if there's no username + if (string.IsNullOrWhiteSpace(username)) + { + return null; + } + + var password = info.Password; + if (string.IsNullOrWhiteSpace(password)) + { + return null; + } + + NameValuePair savedToken = null; + if (!_tokens.TryGetValue(username, out savedToken)) + { + savedToken = new NameValuePair(); + _tokens.TryAdd(username, savedToken); + } + + if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + { + long ticks; + if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) + { + // If it's under 24 hours old we can still use it + if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) + { + return savedToken.Name; + } + } + } + + var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); + savedToken.Name = result; + savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); + return result; + } + finally + { + _tokenSemaphore.Release(); + } + } + + private async Task GetTokenInternal(string username, string password, + CancellationToken cancellationToken) { - throw new NotImplementedException(); + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/token", + UserAgent = UserAgent, + RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", + CancellationToken = cancellationToken + }; + //_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + + // httpOptions.RequestContent); + + using (var responce = await _httpClient.Post(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(responce.Content); + if (root.message == "OK") + { + _logger.Info("Authenticated with Schedules Direct token: " + root.token); + return root.token; + } + + throw new ApplicationException("Could not authenticate with Schedules Direct Error: " + root.message); + } + } + + public string Name + { + get { return "Schedules Direct"; } + } + + public class ScheduleDirect + { + public class Token + { + public int code { get; set; } + public string message { get; set; } + public string serverID { get; set; } + public string token { get; set; } + } + public class Lineup + { + public string lineup { get; set; } + public string name { get; set; } + public string transport { get; set; } + public string location { get; set; } + public string uri { get; set; } + } + + public class Lineups + { + public int code { get; set; } + public string serverID { get; set; } + public string datetime { get; set; } + public List lineups { get; set; } + } + + + public class Headends + { + public string headend { get; set; } + public string transport { get; set; } + public string location { get; set; } + public List lineups { get; set; } + } + + + + public class Map + { + public string stationID { get; set; } + public string channel { get; set; } + public int uhfVhf { get; set; } + public int atscMajor { get; set; } + public int atscMinor { get; set; } + } + + public class Broadcaster + { + public string city { get; set; } + public string state { get; set; } + public string postalcode { get; set; } + public string country { get; set; } + } + + public class Logo + { + public string URL { get; set; } + public int height { get; set; } + public int width { get; set; } + public string md5 { get; set; } + } + + public class Station + { + public string stationID { get; set; } + public string name { get; set; } + public string callsign { get; set; } + public List broadcastLanguage { get; set; } + public List descriptionLanguage { get; set; } + public Broadcaster broadcaster { get; set; } + public string affiliate { get; set; } + public Logo logo { get; set; } + public bool? isCommercialFree { get; set; } + } + + public class Metadata + { + public string lineup { get; set; } + public string modified { get; set; } + public string transport { get; set; } + } + + public class Channel + { + public List map { get; set; } + public List stations { get; set; } + public Metadata metadata { get; set; } + } + + public class RequestScheduleForChannel + { + public string stationID { get; set; } + public List date { get; set; } + } + + + + + public class Rating + { + public string body { get; set; } + public string code { get; set; } + } + + public class Multipart + { + public int partNumber { get; set; } + public int totalParts { get; set; } + } + + public class Program + { + public string programID { get; set; } + public string airDateTime { get; set; } + public int duration { get; set; } + public string md5 { get; set; } + public List audioProperties { get; set; } + public List videoProperties { get; set; } + public List ratings { get; set; } + public bool? @new { get; set; } + public Multipart multipart { get; set; } + } + + + + public class MetadataSchedule + { + public string modified { get; set; } + public string md5 { get; set; } + public string startDate { get; set; } + public string endDate { get; set; } + public int days { get; set; } + } + + public class Day + { + public string stationID { get; set; } + public List programs { get; set; } + public MetadataSchedule metadata { get; set; } + } + + // + public class Title + { + public string title120 { get; set; } + } + + public class EventDetails + { + public string subType { get; set; } + } + + public class Description100 + { + public string descriptionLanguage { get; set; } + public string description { get; set; } + } + + public class Description1000 + { + public string descriptionLanguage { get; set; } + public string description { get; set; } + } + + public class DescriptionsProgram + { + public List description100 { get; set; } + public List description1000 { get; set; } + } + + public class Gracenote + { + public int season { get; set; } + public int episode { get; set; } + } + + public class MetadataPrograms + { + public Gracenote Gracenote { get; set; } + } + + public class ContentRating + { + public string body { get; set; } + public string code { get; set; } + } + + public class Cast + { + public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } + public string characterName { get; set; } + } + + public class Crew + { + public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } + } + + public class QualityRating + { + public string ratingsBody { get; set; } + public string rating { get; set; } + public string minRating { get; set; } + public string maxRating { get; set; } + public string increment { get; set; } + } + + public class Movie + { + public string year { get; set; } + public int duration { get; set; } + public List qualityRating { get; set; } + } + + public class Recommendation + { + public string programID { get; set; } + public string title120 { get; set; } + } + + public class ProgramDetails + { + public string programID { get; set; } + public List titles { get; set; } + public EventDetails eventDetails { get; set; } + public DescriptionsProgram descriptions { get; set; } + public string originalAirDate { get; set; } + public List<string> genres { get; set; } + public string episodeTitle150 { get; set; } + public List<MetadataPrograms> metadata { get; set; } + public List<ContentRating> contentRating { get; set; } + public List<Cast> cast { get; set; } + public List<Crew> crew { get; set; } + public string showType { get; set; } + public bool hasImageArtwork { get; set; } + public string images { get; set; } + public string imageID { get; set; } + public string md5 { get; set; } + public List<string> contentAdvisory { get; set; } + public Movie movie { get; set; } + public List<Recommendation> recommendations { get; set; } + } + + public class Caption + { + public string content { get; set; } + public string lang { get; set; } + } + + public class ImageData + { + public string width { get; set; } + public string height { get; set; } + public string uri { get; set; } + public string size { get; set; } + public string aspect { get; set; } + public string category { get; set; } + public string text { get; set; } + public string primary { get; set; } + public string tier { get; set; } + public Caption caption { get; set; } + } + + public class ShowImages + { + public string programID { get; set; } + public List<ImageData> data { get; set; } + } + } + } } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 89ff3a984..d2b998ae8 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -817,5 +817,8 @@ "ButtonShare": "Share", "HeaderConfirm": "Confirm", "ButtonAdvancedRefresh": "Advanced Refresh", - "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?" + "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?", + "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?", + "HeaderDeleteProvider": "Delete Provider", + "HeaderAddProvider": "Add Provider" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index b6c1321fa..83c2ccf5d 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -695,7 +695,7 @@ "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)", "NotificationOptionCameraImageUploaded": "Camera image uploaded", "NotificationOptionUserLockedOut": "User locked out", - "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.", + "HeaderSendNotificationHelp": "Notifications are delivered to your Emby inbox. Additional options can be installed from the Services tab.", "NotificationOptionServerRestartRequired": "Server restart required", "LabelNotificationEnabled": "Enable this notification", "LabelMonitorUsers": "Monitor activity from:", @@ -1480,5 +1480,8 @@ "HeaderExternalServices": "External Services", "LabelIpAddressPath": "IP Address / Path:", "TabExternalServices": "External Services", - "TabTuners": "Tuners" + "TabTuners": "Tuners", + "HeaderGuideProviders": "Guide Providers", + "AddGuideProviderHelp": "Add a source for TV Guide information", + "LabelZipCode": "Zip Code" } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index ef5bc71ef..1920a9ed7 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -183,6 +183,9 @@ <Content Include="dashboard-ui\livetvguide.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\livetvguidesettings.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\livetvrecordings.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -204,6 +207,9 @@ <Content Include="dashboard-ui\scripts\homeupcoming.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\scripts\livetvguidesettings.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 3fda8ec5c264f077b625247ab29ce504be25774c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 09:23:22 -0400 Subject: update tuner setup --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 56 +++++++++++-- .../LiveTv/IListingsProvider.cs | 6 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 25 +++++- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 6 ++ MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 5 +- .../LiveTv/EmbyTV/EmbyTV.cs | 14 ++-- .../LiveTv/Listings/SchedulesDirect.cs | 73 +++++++++------- .../LiveTv/LiveTvManager.cs | 98 +++++++++++++++++++++- .../LiveTv/TunerHosts/HdHomerun.cs | 8 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 8 ++ .../Localization/JavaScript/javascript.json | 5 +- .../Localization/Server/server.json | 5 +- .../ApplicationHost.cs | 2 +- .../MediaBrowser.WebDashboard.csproj | 4 +- 14 files changed, 256 insertions(+), 59 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 49ba001ce..f40048ce4 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -345,6 +346,31 @@ namespace MediaBrowser.Api.LiveTv public string Id { get; set; } } + [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")] + [Authenticated] + public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo> + { + } + + [Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")] + [Authenticated] + public class DeleteListingProvider : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")] + public string Id { get; set; } + } + + [Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")] + [Authenticated] + public class GetLineups : IReturn<List<NameIdPair>> + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Id { get; set; } + + [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Location { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; @@ -373,20 +399,27 @@ namespace MediaBrowser.Api.LiveTv } } - public void Post(AddTunerHost request) + public object Post(AddListingProvider request) + { + var result = _liveTvManager.SaveListingProvider(request).Result; + return ToOptimizedResult(result); + } + + public void Delete(DeleteListingProvider request) { var config = GetConfiguration(); - config.TunerHosts.Add(new TunerHostInfo - { - Id = Guid.NewGuid().ToString("N"), - Url = request.Url, - Type = request.Type - }); + config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); _config.SaveConfiguration("livetv", config); } + public void Post(AddTunerHost request) + { + var task = _liveTvManager.SaveTunerHost(request); + Task.WaitAll(task); + } + public void Delete(DeleteTunerHost request) { var config = GetConfiguration(); @@ -401,6 +434,13 @@ namespace MediaBrowser.Api.LiveTv return _config.GetConfiguration<LiveTvOptions>("livetv"); } + public async Task<object> Get(GetLineups request) + { + var info = await _liveTvManager.GetLineups(request.Id, request.Location).ConfigureAwait(false); + + return ToOptimizedSerializedResultUsingCache(info); + } + public async Task<object> Get(GetLiveTvInfo request) { var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index beaa4eeaf..e509728bf 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; using System; using System.Collections.Generic; using System.Threading; @@ -9,7 +10,10 @@ namespace MediaBrowser.Controller.LiveTv public interface IListingsProvider { string Name { get; } + string Type { get; } Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken); + Task Validate(ListingsProviderInfo info); + Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 3aa1f66ef..3dbf9a9e9 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -56,12 +56,14 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="id">The identifier.</param> /// <returns>Task.</returns> Task CancelSeriesTimer(string id); - + /// <summary> /// Adds the parts. /// </summary> /// <param name="services">The services.</param> - void AddParts(IEnumerable<ILiveTvService> services); + /// <param name="tunerHosts">The tuner hosts.</param> + /// <param name="listingProviders">The listing providers.</param> + void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders); /// <summary> /// Gets the channels. @@ -337,5 +339,24 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="dto">The dto.</param> /// <param name="user">The user.</param> void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null); + /// <summary> + /// Saves the tuner host. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task SaveTunerHost(TunerHostInfo info); + /// <summary> + /// Saves the listing provider. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info); + /// <summary> + /// Gets the lineups. + /// </summary> + /// <param name="providerId">The provider identifier.</param> + /// <param name="location">The location.</param> + /// <returns>Task<List<NameIdPair>>.</returns> + Task<List<NameIdPair>> GetLineups(string providerId, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 2fa538c60..38ed43bd9 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -46,5 +46,11 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<MediaSourceInfo>.</returns> Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); + /// <summary> + /// Validates the specified information. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task Validate(TunerHostInfo info); } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c78fbe630..90cd8924d 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -28,10 +28,11 @@ namespace MediaBrowser.Model.LiveTv public class ListingsProviderInfo { - public string ProviderName { get; set; } + public string Id { get; set; } + public string Type { get; set; } public string Username { get; set; } public string Password { get; set; } - public string ZipCode { get; set; } public string ListingsId { get; set; } + public string ZipCode { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 26e070921..6e8213ee0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -30,18 +30,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly ItemDataProvider<SeriesTimerInfo> _seriesTimerProvider; private readonly TimerManager _timerProvider; - private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>(); - private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>(); + private readonly LiveTvManager _liveTvManager; - public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager) { _appHpst = appHost; _logger = logger; _httpClient = httpClient; _config = config; + _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; - _tunerHosts.AddRange(appHost.GetExports<ITunerHost>()); - _listingProviders.AddRange(appHost.GetExports<IListingsProvider>()); _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); @@ -76,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List<LiveTvTunerInfo>(); - foreach (var host in _tunerHosts) + foreach (var host in _liveTvManager.TunerHosts) { foreach (var hostInstance in host.GetTunerHosts()) { @@ -104,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var list = new List<ChannelInfo>(); - foreach (var host in _tunerHosts) + foreach (var host in _liveTvManager.TunerHosts) { foreach (var hostInstance in host.GetTunerHosts()) { @@ -288,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return GetConfiguration().ListingProviders .Select(i => { - var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase)); + var provider = _liveTvManager.ListingProviders.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); return provider == null ? null : new Tuple<IListingsProvider, ListingsProviderInfo>(provider, i); }) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 3b7564983..f5b41f3df 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -422,7 +422,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return images; } - public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken) + public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string location, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken); @@ -437,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var options = new HttpRequestOptions() { - Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode, + Url = ApiUrl + "/headends?country=USA&postalcode=" + location, UserAgent = UserAgent, CancellationToken = cancellationToken }; @@ -484,43 +484,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) { - await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - var username = info.Username; + var username = info.Username; - // Reset the token if there's no username - if (string.IsNullOrWhiteSpace(username)) - { - return null; - } + // Reset the token if there's no username + if (string.IsNullOrWhiteSpace(username)) + { + return null; + } - var password = info.Password; - if (string.IsNullOrWhiteSpace(password)) - { - return null; - } + var password = info.Password; + if (string.IsNullOrWhiteSpace(password)) + { + return null; + } - NameValuePair savedToken = null; - if (!_tokens.TryGetValue(username, out savedToken)) - { - savedToken = new NameValuePair(); - _tokens.TryAdd(username, savedToken); - } + NameValuePair savedToken = null; + if (!_tokens.TryGetValue(username, out savedToken)) + { + savedToken = new NameValuePair(); + _tokens.TryAdd(username, savedToken); + } - if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + { + long ticks; + if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) { - long ticks; - if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) + // If it's under 24 hours old we can still use it + if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) { - // If it's under 24 hours old we can still use it - if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) - { - return savedToken.Name; - } + return savedToken.Name; } } + } + await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); savedToken.Name = result; savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); @@ -563,6 +563,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings get { return "Schedules Direct"; } } + public string Type + { + get { return "SchedulesDirect"; } + } + public class ScheduleDirect { public class Token @@ -842,5 +847,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } + public async Task Validate(ListingsProviderInfo info) + { + } + + public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location) + { + return GetHeadends(info, location, CancellationToken.None); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 05bc276b8..a64ce31cf 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -57,6 +57,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ConcurrentDictionary<Guid, Guid> _refreshedPrograms = new ConcurrentDictionary<Guid, Guid>(); + private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>(); + private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>(); + public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { _config = config; @@ -92,9 +95,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv /// Adds the parts. /// </summary> /// <param name="services">The services.</param> - public void AddParts(IEnumerable<ILiveTvService> services) + /// <param name="tunerHosts">The tuner hosts.</param> + /// <param name="listingProviders">The listing providers.</param> + public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders) { _services.AddRange(services); + _tunerHosts.AddRange(tunerHosts); + _listingProviders.AddRange(listingProviders); foreach (var service in _services) { @@ -102,6 +109,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + public List<ITunerHost> TunerHosts + { + get { return _tunerHosts; } + } + + public List<IListingsProvider> ListingProviders + { + get { return _listingProviders; } + } + void service_DataSourceChanged(object sender, EventArgs e) { _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); @@ -2154,5 +2171,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv var user = _userManager.GetUserById(userId); return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); } + + public async Task SaveTunerHost(TunerHostInfo info) + { + info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); + + var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + await provider.Validate(info).ConfigureAwait(false); + + var config = GetConfiguration(); + + var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + + if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) + { + info.Id = Guid.NewGuid().ToString("N"); + config.TunerHosts.Add(info); + } + else + { + config.TunerHosts[index] = info; + } + + _config.SaveConfiguration("livetv", config); + } + + public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info) + { + info = (ListingsProviderInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(ListingsProviderInfo)); + + var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + await provider.Validate(info).ConfigureAwait(false); + + var config = GetConfiguration(); + + var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + + if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) + { + info.Id = Guid.NewGuid().ToString("N"); + config.ListingProviders.Add(info); + } + else + { + config.ListingProviders[index] = info; + } + + _config.SaveConfiguration("livetv", config); + + return info; + } + + + public Task<List<NameIdPair>> GetLineups(string providerId, string location) + { + var config = GetConfiguration(); + + var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase)); + + var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + return provider.GetLineups(info, location); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs index b5b588682..9aacd0c1e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs @@ -3,7 +3,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -15,7 +14,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { @@ -222,5 +220,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts } throw new ApplicationException("Channel not found."); } + + + public async Task Validate(TunerHostInfo info) + { + await GetChannels(info, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 615e07a82..e91bd0f0b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -185,5 +185,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { } } + + public async Task Validate(TunerHostInfo info) + { + if (!File.Exists(info.Url)) + { + throw new FileNotFoundException(); + } + } } } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index d2b998ae8..cea0363f4 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -820,5 +820,8 @@ "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?", "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?", "HeaderDeleteProvider": "Delete Provider", - "HeaderAddProvider": "Add Provider" + "HeaderAddProvider": "Add Provider", + "ErrorAddingTunerDevice": "There was an error adding the tuner device. Please ensure it is accessible and try again.", + "ErrorSavingTvProvider": "There was an error saving the TV provider. Please ensure it is accessible and try again.", + "ErrorGettingTvLineups": "There was an error downloading tv lineups. Please ensure your username and password are correct and try again." } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 83c2ccf5d..fe099dc67 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1483,5 +1483,8 @@ "TabTuners": "Tuners", "HeaderGuideProviders": "Guide Providers", "AddGuideProviderHelp": "Add a source for TV Guide information", - "LabelZipCode": "Zip Code" + "LabelZipCode": "Zip Code:", + "GuideProviderListingsStep": "Step 2: Select Listings", + "GuideProviderLoginStep": "Step 1: Login", + "LabelLineup": "Lineup" } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index fab6682d7..adef0a45f 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -784,7 +784,7 @@ namespace MediaBrowser.Server.Startup.Common ImageProcessor.AddParts(GetExports<IImageEnhancer>()); - LiveTvManager.AddParts(GetExports<ILiveTvService>()); + LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>()); SubtitleManager.AddParts(GetExports<ISubtitleProvider>()); ChapterManager.AddParts(GetExports<IChapterProvider>()); diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 1920a9ed7..bc2b8eb7a 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -183,7 +183,7 @@ <Content Include="dashboard-ui\livetvguide.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\livetvguidesettings.html"> + <Content Include="dashboard-ui\livetvguideprovider-scd.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> <Content Include="dashboard-ui\livetvrecordings.html"> @@ -207,7 +207,7 @@ <Content Include="dashboard-ui\scripts\homeupcoming.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\scripts\livetvguidesettings.js"> + <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> -- cgit v1.2.3 From ba9ed26c4a60b29f25c0cf53d215b617142c0fc3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 19:40:54 -0400 Subject: update emby tv --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- MediaBrowser.Api/Playback/StreamState.cs | 2 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 8 ++ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 4 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + .../Library/MediaSourceManager.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 130 +++++++++++++++++---- .../LiveTv/EmbyTV/ItemDataProvider.cs | 5 +- .../LiveTv/Listings/SchedulesDirect.cs | 51 ++++++-- .../LiveTv/LiveTvManager.cs | 4 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 24 ++-- .../TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 12 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 62 ++++++---- .../LiveTv/TunerHosts/M3UTunerHost.cs | 10 +- .../Localization/Server/server.json | 2 +- 17 files changed, 236 insertions(+), 87 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e7885a3f8..8505b5d3a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -924,7 +924,7 @@ namespace MediaBrowser.Api.Playback state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 02b7720a4..4df696096 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Playback private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId)) + if ((MediaSource.RequiresClosing ?? false) && string.IsNullOrWhiteSpace(Request.LiveStreamId)) { try { diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 38ed43bd9..c9a96a9ca 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -47,6 +47,14 @@ namespace MediaBrowser.Controller.LiveTv /// <returns>Task<MediaSourceInfo>.</returns> Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); /// <summary> + /// Gets the channel stream media sources. + /// </summary> + /// <param name="info">The information.</param> + /// <param name="channelId">The channel identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task<List<MediaSourceInfo>>.</returns> + Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken); + /// <summary> /// Validates the specified information. /// </summary> /// <param name="info">The information.</param> diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index fbfe79272..9153045e6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -436,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Encoder state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index efce5abb0..bb32ac95b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -137,7 +137,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing) + if (MediaSource.RequiresClosing ?? false) { try { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 8897edcbd..75edc6a52 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Model.Dto public bool SupportsDirectStream { get; set; } public bool SupportsDirectPlay { get; set; } - public bool RequiresOpening { get; set; } + public bool? RequiresOpening { get; set; } public string OpenToken { get; set; } - public bool RequiresClosing { get; set; } + public bool? RequiresClosing { get; set; } public string LiveStreamId { get; set; } public int? BufferMs { get; set; } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 90cd8924d..3fc841645 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -34,5 +34,6 @@ namespace MediaBrowser.Model.LiveTv public string Password { get; set; } public string ListingsId { get; set; } public string ZipCode { get; set; } + public string Country { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 9b46a8057..765acd578 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -439,7 +439,7 @@ namespace MediaBrowser.Server.Implementations.Library LiveStreamInfo current; if (_openStreams.TryGetValue(id, out current)) { - if (current.MediaSource.RequiresClosing) + if (current.MediaSource.RequiresClosing ?? false) { var tuple = GetProvider(id); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 37b6bf086..c32b8da10 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.LiveTv; @@ -74,20 +75,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List<LiveTvTunerInfo>(); - foreach (var host in _liveTvManager.TunerHosts) + foreach (var hostInstance in GetTunerHosts()) { - foreach (var hostInstance in host.GetTunerHosts()) + try { - try - { - var tuners = await host.GetTunerInfos(hostInstance, cancellationToken).ConfigureAwait(false); + var tuners = await hostInstance.Item1.GetTunerInfos(hostInstance.Item2, cancellationToken).ConfigureAwait(false); - list.AddRange(tuners); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting tuners", ex); - } + list.AddRange(tuners); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting tuners", ex); } } @@ -102,20 +100,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var list = new List<ChannelInfo>(); - foreach (var host in _liveTvManager.TunerHosts) + foreach (var hostInstance in GetTunerHosts()) { - foreach (var hostInstance in host.GetTunerHosts()) + try { - try - { - var channels = await host.GetChannels(hostInstance, cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.Item1.GetChannels(hostInstance.Item2, cancellationToken).ConfigureAwait(false); + var newChannels = channels.ToList(); - list.AddRange(channels); - } - catch (Exception ex) + foreach (var channel in newChannels) { - _logger.ErrorException("Error getting channels", ex); + channel.Id = hostInstance.Item1.Type.GetMD5().ToString("N") + "-" + channel.Id; } + + list.AddRange(newChannels); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channels", ex); } } @@ -130,6 +131,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return list; } + private List<Tuple<ITunerHost, TunerHostInfo>> GetTunerHosts() + { + return GetConfiguration().TunerHosts + .Select(i => + { + var provider = _liveTvManager.TunerHosts.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + return provider == null ? null : new Tuple<ITunerHost, TunerHostInfo>(provider, i); + }) + .Where(i => i != null) + .ToList(); + } + public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { var remove = _seriesTimerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); @@ -255,14 +269,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult((IEnumerable<SeriesTimerInfo>)_seriesTimerProvider.GetAll()); } + private string GetOriginalChannelId(string channelId) + { + var parts = channelId.Split('-'); + + return string.Join("-", parts.Skip(1).ToArray()); + } + public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { foreach (var provider in GetListingProviders()) { - var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelId, startDateUtc, endDateUtc, cancellationToken) + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, GetOriginalChannelId(channelId), startDateUtc, endDateUtc, cancellationToken) .ConfigureAwait(false); var list = programs.ToList(); + // Replace the value that came from the provider with a normalized value + foreach (var program in list) + { + program.ChannelId = channelId; + } + if (list.Count > 0) { return list; @@ -290,14 +317,67 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV throw new NotImplementedException(); } - public Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) { - throw new NotImplementedException(); + _logger.Info("Streaming Channel " + channelId); + + var configurationId = channelId.Split('-')[0]; + + foreach (var hostInstance in GetTunerHosts()) + { + if (!string.Equals(configurationId, hostInstance.Item1.Type.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + if (!string.IsNullOrWhiteSpace(streamId)) + { + var originalStreamId = string.Join("-", streamId.Split('-').Skip(1).ToArray()); + + if (!string.Equals(hostInstance.Item2.Id, originalStreamId, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + } + + MediaSourceInfo mediaSourceInfo = null; + try + { + mediaSourceInfo = await hostInstance.Item1.GetChannelStream(hostInstance.Item2, GetOriginalChannelId(channelId), streamId, cancellationToken).ConfigureAwait(false); + } + catch (ApplicationException e) + { + _logger.Info(e.Message); + continue; + } + + mediaSourceInfo.Id = Guid.NewGuid().ToString("N"); + return mediaSourceInfo; + } + + throw new ApplicationException("Tuner not found."); } - public Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) + public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var configurationId = channelId.Split('-')[0]; + + foreach (var hostInstance in GetTunerHosts()) + { + if (string.Equals(configurationId, hostInstance.Item1.Type.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase)) + { + var sources = await hostInstance.Item1.GetChannelStreamMediaSources(hostInstance.Item2, GetOriginalChannelId(channelId), cancellationToken).ConfigureAwait(false); + + foreach (var source in sources) + { + source.Id = hostInstance.Item2.Id + "-" + source.Id; + } + + return sources; + } + } + + throw new ApplicationException("Tuner not found."); } public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index e7feeee5a..75dec5f97 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -68,9 +68,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private void UpdateList(List<T> newList) { + var file = _dataPath + ".json"; + Directory.CreateDirectory(Path.GetDirectoryName(file)); + lock (_fileDataLock) { - _jsonSerializer.SerializeToFile(newList, _dataPath + ".json"); + _jsonSerializer.SerializeToFile(newList, file); _items = newList; } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index ed265d416..72a965c6a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -218,7 +218,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details) { - _logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); + //_logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); DateTime endAt = startAt.AddSeconds(programInfo.duration); @@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _logger.Info("Headends on account "); var countryParam = string.Equals("ca", country, StringComparison.OrdinalIgnoreCase) - ? "Canada" + ? "can" : "USA"; var options = new HttpRequestOptions() @@ -562,6 +562,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings get { return "SchedulesDirect"; } } + private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + _logger.Info("Headends on account "); + + var options = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + options.RequestHeaders["token"] = token; + + using (Stream responce = await _httpClient.Get(options).ConfigureAwait(false)) + { + var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(responce); + + return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); + } + } + + public async Task Validate(ListingsProviderInfo info) + { + var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false); + + if (!hasLineup) + { + await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); + } + } + + public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location) + { + return GetHeadends(info, country, location, CancellationToken.None); + } + public class ScheduleDirect { public class Token @@ -841,14 +879,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } - public async Task Validate(ListingsProviderInfo info) - { - //await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); - } - - public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location) - { - return GetHeadends(info, country, location, CancellationToken.None); - } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 5be90e6cc..6ef565129 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -367,7 +367,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; @@ -384,7 +384,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 5ebb79629..cf34b6b99 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. private const char StreamIdDelimeter = '_'; - private const string StreamIdDelimeterString = "|"; + private const string StreamIdDelimeterString = "_"; private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(ILiveTvItem item, CancellationToken cancellationToken) { @@ -86,14 +86,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var source in list) { source.Type = MediaSourceType.Default; - source.RequiresOpening = true; - source.BufferMs = source.BufferMs ?? 1500; - var openKeys = new List<string>(); - openKeys.Add(item.GetType().Name); - openKeys.Add(item.Id.ToString("N")); - openKeys.Add(source.Id ?? string.Empty); - source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); + if (!source.RequiresOpening.HasValue) + { + source.RequiresOpening = true; + } + + if (source.RequiresOpening.HasValue && source.RequiresOpening.Value) + { + var openKeys = new List<string>(); + openKeys.Add(item.GetType().Name); + openKeys.Add(item.Id.ToString("N")); + openKeys.Add(source.Id ?? string.Empty); + source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); + } + + source.BufferMs = source.BufferMs ?? 1500; // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index 4777003d6..cc2bb2d52 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -72,6 +72,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return; } + // Strip off the port + url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); + await _liveTvManager.SaveTunerHost(new TunerHostInfo { Type = HdHomerunHost.DeviceType, @@ -103,13 +106,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = url.TrimEnd('/'); - // If there isn't a port, add the default port of 80 - if (url.Split(':').Length < 3) - { - url += ":80"; - } - - return url; + // Strip off the port + return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); } private LiveTvOptions GetConfiguration() diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 187569ab4..d9f1541c8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var options = new HttpRequestOptions { - Url = string.Format("{0}/lineup.json", GetApiUrl(info)), + Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)), CancellationToken = cancellationToken }; using (var stream = await _httpClient.Get(options)) @@ -79,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/", GetApiUrl(info)), + Url = string.Format("{0}/", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/tuners.html", GetApiUrl(info)), + Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public string GetApiUrl(TunerHostInfo info) + private string GetApiUrl(TunerHostInfo info, bool isPlayback) { var url = info.Url; @@ -137,7 +137,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = "http://" + url; } - return url.TrimEnd('/'); + var uri = new Uri(url); + + if (isPlayback) + { + var builder = new UriBuilder(uri); + builder.Port = 5004; + uri = builder.Uri; + } + + return uri.AbsoluteUri.TrimEnd('/'); } private static string StripXML(string source) @@ -187,21 +196,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); } - public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, string profile) { - var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); - var tuners = await GetTunerInfos(info, cancellationToken).ConfigureAwait(false); - - var channel = channels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase)); - if (channel != null) + var mediaSource = new MediaSourceInfo { - if (tuners.FindIndex(t => t.Status == LiveTvTunerStatus.Available) >= 0) - { - return new MediaSourceInfo - { - Path = GetApiUrl(info) + "/auto/v" + channelId, - Protocol = MediaProtocol.Http, - MediaStreams = new List<MediaStream> + Path = GetApiUrl(info, true) + "/auto/v" + channelId, + Protocol = MediaProtocol.Http, + MediaStreams = new List<MediaStream> { new MediaStream { @@ -217,15 +218,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun Index = -1 } - } - }; - } + }, + RequiresOpening = false, + RequiresClosing = false, + BufferMs = 1000 + }; - throw new ApplicationException("No tuners avaliable."); - } - throw new ApplicationException("Channel not found."); + return mediaSource; } + public Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + { + var list = new List<MediaSourceInfo>(); + + list.Add(GetMediaSource(info, channelId, null)); + + return Task.FromResult(list); + } + + public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + { + return GetMediaSource(info, channelId, null); + } public async Task Validate(TunerHostInfo info) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index e91bd0f0b..91f25bbee 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -171,7 +171,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts Index = -1 } - } + }, + RequiresOpening = false, + RequiresClosing = false }; } throw new ApplicationException("Host doesnt provide this channel"); @@ -193,5 +195,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts throw new FileNotFoundException(); } } + + + public Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 24df7c983..194d406f3 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1489,5 +1489,5 @@ "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", "LabelLineup": "Lineup", - "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service plugin for more Live TV options." + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options." } -- cgit v1.2.3 From 77afd4ba544abf2c92cd6d098e997dfc2d9b39c9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Fri, 24 Jul 2015 11:20:11 -0400 Subject: update live tv --- .../HttpClientManager/HttpClientManager.cs | 2 +- MediaBrowser.Model/Session/GeneralCommandType.cs | 4 +++- MediaBrowser.Model/Session/PlaybackProgressInfo.cs | 12 ++++++++++++ .../Library/UserViewManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 20 ++++++++++---------- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 3 ++- .../Playlists/PlaylistManager.cs | 15 +++++++++------ .../ApplicationHost.cs | 2 +- 8 files changed, 39 insertions(+), 21 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 18441161f..89f405e8a 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression) { - var request = WebRequest.Create(options.Url); + var request = CreateWebRequest(options.Url); var httpWebRequest = request as HttpWebRequest; if (httpWebRequest != null) diff --git a/MediaBrowser.Model/Session/GeneralCommandType.cs b/MediaBrowser.Model/Session/GeneralCommandType.cs index f8773a246..dcb3b20ca 100644 --- a/MediaBrowser.Model/Session/GeneralCommandType.cs +++ b/MediaBrowser.Model/Session/GeneralCommandType.cs @@ -33,6 +33,8 @@ ToggleFullscreen = 25, DisplayContent = 26, GoToSearch = 27, - DisplayMessage = 28 + DisplayMessage = 28, + SetRepeatAll = 29, + SetRepeatOne = 30 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs index a7ca09c15..345931a62 100644 --- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs @@ -88,5 +88,17 @@ namespace MediaBrowser.Model.Session /// </summary> /// <value>The play session identifier.</value> public string PlaySessionId { get; set; } + /// <summary> + /// Gets or sets the repeat mode. + /// </summary> + /// <value>The repeat mode.</value> + public RepeatMode RepeatMode { get; set; } + } + + public enum RepeatMode + { + RepeatNone = 0, + RepeatAll = 1, + RepeatOne = 2 } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 69600f0fe..14c5c9a03 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -99,7 +99,7 @@ namespace MediaBrowser.Server.Implementations.Library list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); } - parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) + parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) .ToList(); if (parents.Count > 0) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 6ef565129..3ca60ec51 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -544,16 +544,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv var replaceImages = new List<ImageType>(); - if (!string.Equals(item.ProviderImageUrl, channelInfo.ImageUrl, StringComparison.OrdinalIgnoreCase)) - { - isNew = true; - replaceImages.Add(ImageType.Primary); - } - if (!string.Equals(item.ProviderImagePath, channelInfo.ImagePath, StringComparison.OrdinalIgnoreCase)) - { - isNew = true; - replaceImages.Add(ImageType.Primary); - } + //if (!string.Equals(item.ProviderImageUrl, channelInfo.ImageUrl, StringComparison.OrdinalIgnoreCase)) + //{ + // isNew = true; + // replaceImages.Add(ImageType.Primary); + //} + //if (!string.Equals(item.ProviderImagePath, channelInfo.ImagePath, StringComparison.OrdinalIgnoreCase)) + //{ + // isNew = true; + // replaceImages.Add(ImageType.Primary); + //} item.ProviderImageUrl = channelInfo.ImageUrl; item.HasProviderImage = channelInfo.HasImage; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 50303a89a..eb8f8f80e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -325,7 +325,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) { - list.Add(GetMediaSource(info, channelId, "heavy")); + list.Insert(0, GetMediaSource(info, channelId, "heavy")); + list.Add(GetMediaSource(info, channelId, "internet480")); list.Add(GetMediaSource(info, channelId, "internet360")); list.Add(GetMediaSource(info, channelId, "internet240")); diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs index 311cb9b51..857cf743f 100644 --- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs @@ -23,14 +23,16 @@ namespace MediaBrowser.Server.Implementations.Playlists private readonly ILibraryMonitor _iLibraryMonitor; private readonly ILogger _logger; private readonly IUserManager _userManager; + private readonly IProviderManager _providerManager; - public PlaylistManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger, IUserManager userManager) + public PlaylistManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger, IUserManager userManager, IProviderManager providerManager) { _libraryManager = libraryManager; _fileSystem = fileSystem; _iLibraryMonitor = iLibraryMonitor; _logger = logger; _userManager = userManager; + _providerManager = providerManager; } public IEnumerable<Playlist> GetPlaylists(string userId) @@ -193,11 +195,11 @@ namespace MediaBrowser.Server.Implementations.Playlists playlist.LinkedChildren.AddRange(list); await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - await playlist.RefreshMetadata(new MetadataRefreshOptions + + _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions { ForceSave = true - - }, CancellationToken.None).ConfigureAwait(false); + }); } public async Task RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds) @@ -220,10 +222,11 @@ namespace MediaBrowser.Server.Implementations.Playlists .ToList(); await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - await playlist.RefreshMetadata(new MetadataRefreshOptions + + _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions { ForceSave = true - }, CancellationToken.None).ConfigureAwait(false); + }); } public Folder GetPlaylistsFolder(string userId) diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 5fd1dca43..5e5babbb4 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -493,7 +493,7 @@ namespace MediaBrowser.Server.Startup.Common CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager")); RegisterSingleInstance(CollectionManager); - PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager); + PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager); RegisterSingleInstance<IPlaylistManager>(PlaylistManager); LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager); -- cgit v1.2.3 From b19451284351d5b753067522e9ef82b873c08770 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sat, 25 Jul 2015 14:11:46 -0400 Subject: update tuners --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 ++++---- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 4 +++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 9 ++++++++- .../Localization/Server/server.json | 6 ++++-- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 12 ++++++++++++ 8 files changed, 34 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 6c61ef66f..b0359194c 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -334,7 +334,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")] [Authenticated] - public class AddTunerHost : TunerHostInfo, IReturnVoid + public class AddTunerHost : TunerHostInfo, IReturn<TunerHostInfo> { } @@ -419,10 +419,10 @@ namespace MediaBrowser.Api.LiveTv _config.SaveConfiguration("livetv", config); } - public void Post(AddTunerHost request) + public async Task<object> Post(AddTunerHost request) { - var task = _liveTvManager.SaveTunerHost(request); - Task.WaitAll(task); + var result = await _liveTvManager.SaveTunerHost(request).ConfigureAwait(false); + return ToOptimizedResult(result); } public void Delete(DeleteTunerHost request) diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 259f6925b..53ad6dbdc 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -344,7 +344,7 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <param name="info">The information.</param> /// <returns>Task.</returns> - Task SaveTunerHost(TunerHostInfo info); + Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info); /// <summary> /// Saves the listing provider. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 3fc841645..004ee2ce6 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Model.LiveTv public string Id { get; set; } public string Url { get; set; } public string Type { get; set; } + public bool ImportFavoritesOnly { get; set; } } public class ListingsProviderInfo diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d539562b8..b7091ee09 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2172,7 +2172,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); } - public async Task SaveTunerHost(TunerHostInfo info) + public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info) { info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); @@ -2202,6 +2202,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv _config.SaveConfiguration("livetv", config); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); + + return info; } public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index cc2bb2d52..10baffea6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } // Strip off the port - url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); + url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/'); await _liveTvManager.SaveTunerHost(new TunerHostInfo { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 1e30a4fd8..682abd20f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (root != null) { - return root.Select(i => new ChannelInfo + var result = root.Select(i => new ChannelInfo { Name = i.GuideName, Number = i.GuideNumber.ToString(CultureInfo.InvariantCulture), @@ -68,6 +68,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun IsFavorite = i.Favorite }); + + if (info.ImportFavoritesOnly) + { + result = result.Where(i => (i.IsFavorite ?? true)).ToList(); + } + + return result; } return new List<ChannelInfo>(); } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 2c2fd76a7..e5a36b12f 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1480,7 +1480,7 @@ "ButtonAddDevice": "Add Device", "HeaderAddDevice": "Add Device", "HeaderExternalServices": "External Services", - "LabelIpAddressPath": "IP Address / Path:", + "LabelTunerIpAddress": "Tuner IP Address:", "TabExternalServices": "External Services", "TabTuners": "Tuners", "HeaderGuideProviders": "Guide Providers", @@ -1489,5 +1489,7 @@ "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", "LabelLineup": "Lineup:", - "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options." + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options.", + "LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite", + "ImportFavoriteChannelsHelp": "If enabled, only channels that are marked as favorite on the tuner device will be imported." } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index bc2b8eb7a..982d68461 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -195,6 +195,12 @@ <Content Include="dashboard-ui\livetvtimers.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\livetvtunerprovider-hdhomerun.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="dashboard-ui\livetvtunerprovider-m3u.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\mypreferenceshome.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -210,6 +216,12 @@ <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="dashboard-ui\scripts\livetvtunerprovider-m3u.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 1bf9c446d93f5b9aae9a8f24439690beb0be3295 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 26 Jul 2015 17:02:23 -0400 Subject: update hdhomerun --- .../Configuration/ServerConfiguration.cs | 138 ++++++++++++++++++++- MediaBrowser.Model/Session/GeneralCommandType.cs | 3 +- MediaBrowser.Model/Users/UserPolicy.cs | 4 + .../LiveTv/Listings/SchedulesDirect.cs | 98 ++++++++------- .../Localization/Server/server.json | 5 +- 5 files changed, 198 insertions(+), 50 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 19403a55e..0a2fabc1b 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -283,7 +283,59 @@ namespace MediaBrowser.Model.Configuration { new ImageOption { - Limit = 2, + Limit = 1, + MinWidth = 1280, + Type = ImageType.Backdrop + }, + + // Don't download this by default as it's rarely used. + new ImageOption + { + Limit = 0, + Type = ImageType.Art + }, + + // Don't download this by default as it's rarely used. + new ImageOption + { + Limit = 0, + Type = ImageType.Disc + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Primary + }, + + new ImageOption + { + Limit = 0, + Type = ImageType.Banner + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Thumb + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Logo + } + } + }, + + new MetadataOptions(1, 1280) + { + ItemType = "MusicVideo", + ImageOptions = new [] + { + new ImageOption + { + Limit = 1, MinWidth = 1280, Type = ImageType.Backdrop }, @@ -335,7 +387,7 @@ namespace MediaBrowser.Model.Configuration { new ImageOption { - Limit = 2, + Limit = 1, MinWidth = 1280, Type = ImageType.Backdrop }, @@ -432,9 +484,89 @@ namespace MediaBrowser.Model.Configuration } }, + new MetadataOptions(1, 1280) + { + ItemType = "BoxSet", + ImageOptions = new [] + { + new ImageOption + { + Limit = 1, + MinWidth = 1280, + Type = ImageType.Backdrop + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Primary + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Thumb + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Logo + }, + + // Don't download this by default as it's rarely used. + new ImageOption + { + Limit = 0, + Type = ImageType.Art + }, + + // Don't download this by default as it's rarely used. + new ImageOption + { + Limit = 0, + Type = ImageType.Disc + }, + + // Don't download this by default as it's rarely used. + new ImageOption + { + Limit = 0, + Type = ImageType.Banner + } + } + }, + new MetadataOptions(0, 1280) { - ItemType = "Season" + ItemType = "Season", + ImageOptions = new [] + { + new ImageOption + { + Limit = 0, + MinWidth = 1280, + Type = ImageType.Backdrop + }, + + new ImageOption + { + Limit = 1, + Type = ImageType.Primary + }, + + new ImageOption + { + Limit = 0, + Type = ImageType.Banner + }, + + new ImageOption + { + Limit = 0, + Type = ImageType.Thumb + } + } } }; } diff --git a/MediaBrowser.Model/Session/GeneralCommandType.cs b/MediaBrowser.Model/Session/GeneralCommandType.cs index dcb3b20ca..79220f066 100644 --- a/MediaBrowser.Model/Session/GeneralCommandType.cs +++ b/MediaBrowser.Model/Session/GeneralCommandType.cs @@ -34,7 +34,6 @@ DisplayContent = 26, GoToSearch = 27, DisplayMessage = 28, - SetRepeatAll = 29, - SetRepeatOne = 30 + SetRepeatMode = 29 } } \ No newline at end of file diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index b3040d6f8..16b4b673d 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -80,6 +80,10 @@ namespace MediaBrowser.Model.Users EnableLiveTvManagement = true; EnableLiveTvAccess = true; + // Without this on by default, admins won't be able to do this + // Improve in the future + EnableLiveTvManagement = true; + EnableSharedDeviceControl = true; BlockedTags = new string[] { }; diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 5fd9745a1..64599bc58 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -151,65 +151,72 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(info.ListingsId)) + { + throw new Exception("ListingsId required"); + } + var token = await GetToken(info, cancellationToken); + if (string.IsNullOrWhiteSpace(token)) + { + throw new Exception("token required"); + } + _channelPair.Clear(); - if (!String.IsNullOrWhiteSpace(token) && !String.IsNullOrWhiteSpace(info.ListingsId)) + var httpOptions = new HttpRequestOptions() { - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/lineups/" + info.ListingsId, - UserAgent = UserAgent, - CancellationToken = cancellationToken - }; + Url = ApiUrl + "/lineups/" + info.ListingsId, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; - httpOptions.RequestHeaders["token"] = token; - - using (var response = await _httpClient.Get(httpOptions)) + httpOptions.RequestHeaders["token"] = token; + + using (var response = await _httpClient.Get(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response); + _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); + _logger.Info("Mapping Stations to Channel"); + foreach (ScheduleDirect.Map map in root.map) { - var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response); - _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); - _logger.Info("Mapping Stations to Channel"); - foreach (ScheduleDirect.Map map in root.map) - { - var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); - _logger.Debug("Found channel: " + channel + " in Schedules Direct"); - var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); + var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); + _logger.Debug("Found channel: " + channel + " in Schedules Direct"); + var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); - if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) - { - _channelPair.TryAdd(channel, schChannel); - } + if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) + { + _channelPair.TryAdd(channel, schChannel); } - _logger.Info("Added " + _channelPair.Count() + " channels to the dictionary"); + } + _logger.Info("Added " + _channelPair.Count() + " channels to the dictionary"); - foreach (ChannelInfo channel in channels) + foreach (ChannelInfo channel in channels) + { + // Helper.logger.Info("Modifyin channel " + channel.Number); + if (_channelPair.ContainsKey(channel.Number)) { - // Helper.logger.Info("Modifyin channel " + channel.Number); - if (_channelPair.ContainsKey(channel.Number)) + string channelName; + if (_channelPair[channel.Number].logo != null) { - string channelName; - if (_channelPair[channel.Number].logo != null) - { - channel.ImageUrl = _channelPair[channel.Number].logo.URL; - channel.HasImage = true; - } - if (_channelPair[channel.Number].affiliate != null) - { - channelName = _channelPair[channel.Number].affiliate; - } - else - { - channelName = _channelPair[channel.Number].name; - } - channel.Name = channelName; + channel.ImageUrl = _channelPair[channel.Number].logo.URL; + channel.HasImage = true; + } + if (_channelPair[channel.Number].affiliate != null) + { + channelName = _channelPair[channel.Number].affiliate; } else { - _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + - channel.Name); + channelName = _channelPair[channel.Number].name; } + channel.Name = channelName; + } + else + { + _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + + channel.Name); } } } @@ -572,6 +579,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var token = await GetToken(info, cancellationToken); + if (string.IsNullOrWhiteSpace(token)) + { + throw new Exception("token required"); + } + _logger.Info("Headends on account "); var options = new HttpRequestOptions() diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index e5a36b12f..e06bcea34 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1459,7 +1459,7 @@ "ButtonUnlockGuide": "Unlock Guide", "LabelEnableFullScreen": "Enable fullscreen mode", "LabelEnableChromecastAc3Passthrough": "Enable Chromecast AC3 Passthrough", - "LabelSyncPath": "Synced content path:", + "OptionSyncToSDCard": "Synced to external SD card", "LabelEmail": "Email:", "LabelUsername": "Username:", "HeaderSignUp": "Sign Up", @@ -1491,5 +1491,6 @@ "LabelLineup": "Lineup:", "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options.", "LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite", - "ImportFavoriteChannelsHelp": "If enabled, only channels that are marked as favorite on the tuner device will be imported." + "ImportFavoriteChannelsHelp": "If enabled, only channels that are marked as favorite on the tuner device will be imported.", + "ButtonRepeat": "Repeat" } -- cgit v1.2.3 From 7f9a2f1af6c43ccf49b417884583c999e53298cd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Mon, 27 Jul 2015 12:21:18 -0400 Subject: add path help messages --- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 5 ----- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 6 ++++++ MediaBrowser.Model/System/SystemInfo.cs | 5 +++++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 1 + MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 6 +++--- .../LiveTv/RefreshChannelsScheduledTask.cs | 3 ++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 5 ----- .../LiveTv/TunerHosts/M3UTunerHost.cs | 5 ----- .../Localization/JavaScript/javascript.json | 7 ++++--- MediaBrowser.Server.Startup.Common/ApplicationHost.cs | 3 ++- 10 files changed, 23 insertions(+), 23 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index c9a96a9ca..a6c8021d9 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -19,11 +19,6 @@ namespace MediaBrowser.Controller.LiveTv /// <value>The type.</value> string Type { get; } /// <summary> - /// Gets the tuner hosts. - /// </summary> - /// <returns>List<TunerHostInfo>.</returns> - List<TunerHostInfo> GetTunerHosts(); - /// <summary> /// Gets the channels. /// </summary> /// <param name="info">The information.</param> diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 004ee2ce6..c5e8f4636 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -25,6 +25,12 @@ namespace MediaBrowser.Model.LiveTv public string Url { get; set; } public string Type { get; set; } public bool ImportFavoritesOnly { get; set; } + public bool IsEnabled { get; set; } + + public TunerHostInfo() + { + IsEnabled = true; + } } public class ListingsProviderInfo diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 8c1fc759f..094c4fda6 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -13,6 +13,11 @@ namespace MediaBrowser.Model.System /// </summary> /// <value>The operating sytem.</value> public string OperatingSystem { get; set; } + /// <summary> + /// Gets or sets the display name of the operating system. + /// </summary> + /// <value>The display name of the operating system.</value> + public string OperatingSystemDisplayName { get; set; } /// <summary> /// Gets or sets a value indicating whether this instance is running as service. diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c32b8da10..d5bfc5449 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -134,6 +134,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private List<Tuple<ITunerHost, TunerHostInfo>> GetTunerHosts() { return GetConfiguration().TunerHosts + .Where(i => i.IsEnabled) .Select(i => { var provider = _liveTvManager.TunerHosts.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index b7091ee09..d8e60be5a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2127,7 +2127,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private bool IsLiveTvEnabled(User user) { - return user.Policy.EnableLiveTvAccess && Services.Count > 0; + return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count(i => i.IsEnabled) > 0); } public IEnumerable<User> GetEnabledUsers() @@ -2175,7 +2175,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info) { info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); - + var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); if (provider == null) @@ -2236,7 +2236,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _config.SaveConfiguration("livetv", config); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); - + return info; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index 7cb616d3f..fa1a8b3e7 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -5,6 +5,7 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Tasks; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv @@ -61,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public bool IsHidden { - get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; } + get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count(i => i.IsEnabled) == 0; } } public bool IsEnabled diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 55d3e6a33..c01eb63ab 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -207,11 +207,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return _config.GetConfiguration<LiveTvOptions>("livetv"); } - public List<TunerHostInfo> GetTunerHosts() - { - return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); - } - private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, string profile) { int? width = null; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 91f25bbee..bb31390f2 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -124,11 +124,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return _config.GetConfiguration<LiveTvOptions>("livetv"); } - public List<TunerHostInfo> GetTunerHosts() - { - return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); - } - public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index acd54cb0f..2e61d181b 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -288,6 +288,7 @@ "HeaderSelectPath": "Select Path", "ButtonNetwork": "Network", "MessageDirectoryPickerInstruction": "Network paths can be entered manually in the event the Network button fails to locate your devices. For example, {0} or {1}.", + "MessageDirectoryPickerBSDInstruction": "For BSD, you may need to configure storage within your FreeNAS Jail in order to allow Emby to access it.", "HeaderMenu": "Menu", "ButtonOpen": "Open", "ButtonOpenInNewTab": "Open in new tab", @@ -828,7 +829,7 @@ "ErrorPleaseSelectLineup": "Please select a lineup and try again. If no lineups are available, then please check that your username, password, and postal code is correct.", "HeaderTryCinemaMode": "Try Cinema Mode", "ButtonBecomeSupporter": "Become an Emby Supporter", - "ButtonClosePlayVideo": "Close and play my video", - "MessageDidYouKnowCinemaMode": "Did you know that by becoming an Emby Supporter, you can enhance your experience with features like Cinema Mode?", - "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature." + "ButtonClosePlayVideo": "Close and play my media", + "MessageDidYouKnowCinemaMode": "Did you know that by becoming an Emby Supporter, you can enhance your experience with features like Cinema Mode?", + "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature." } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 5e5babbb4..b554e0d1c 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -1055,7 +1055,8 @@ namespace MediaBrowser.Server.Startup.Common HttpServerPortNumber = HttpPort, SupportsHttps = SupportsHttps, HttpsPortNumber = HttpsPort, - OperatingSystem = OperatingSystemDisplayName, + OperatingSystem = NativeApp.Environment.OperatingSystem.ToString(), + OperatingSystemDisplayName = OperatingSystemDisplayName, CanSelfRestart = CanSelfRestart, CanSelfUpdate = CanSelfUpdate, WanAddress = ConnectManager.WanApiAddress, -- cgit v1.2.3 From a2b9ee8ac6c760c02cd1cc42d0fe56137b77802e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 30 Jul 2015 10:34:46 -0400 Subject: update startup wizard --- MediaBrowser.Api/UserLibrary/PlaystateService.cs | 6 +++++- MediaBrowser.Model/Session/PlayerStateInfo.cs | 6 ++++++ MediaBrowser.Server.Implementations/Session/SessionManager.cs | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index 5f32725d8..7002a3703 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -185,6 +185,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public string PlaySessionId { get; set; } + + [ApiMember(Name = "RepeatMode", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public RepeatMode RepeatMode { get; set; } } /// <summary> @@ -325,7 +328,8 @@ namespace MediaBrowser.Api.UserLibrary VolumeLevel = request.VolumeLevel, PlayMethod = request.PlayMethod, PlaySessionId = request.PlaySessionId, - LiveStreamId = request.LiveStreamId + LiveStreamId = request.LiveStreamId, + RepeatMode = request.RepeatMode }); } diff --git a/MediaBrowser.Model/Session/PlayerStateInfo.cs b/MediaBrowser.Model/Session/PlayerStateInfo.cs index c9afef8e0..f78842e29 100644 --- a/MediaBrowser.Model/Session/PlayerStateInfo.cs +++ b/MediaBrowser.Model/Session/PlayerStateInfo.cs @@ -55,5 +55,11 @@ /// </summary> /// <value>The play method.</value> public PlayMethod? PlayMethod { get; set; } + + /// <summary> + /// Gets or sets the repeat mode. + /// </summary> + /// <value>The repeat mode.</value> + public RepeatMode RepeatMode { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 560d203db..c2160f48a 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -366,6 +366,7 @@ namespace MediaBrowser.Server.Implementations.Session session.PlayState.AudioStreamIndex = info.AudioStreamIndex; session.PlayState.SubtitleStreamIndex = info.SubtitleStreamIndex; session.PlayState.PlayMethod = info.PlayMethod; + session.PlayState.RepeatMode = info.RepeatMode; } /// <summary> -- cgit v1.2.3 From 901dab5760d2e63e9c98fbe5cdaa816bc105e5b7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 30 Jul 2015 21:52:11 -0400 Subject: rework transcoding settings --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 98 ++++------------------ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 43 +--------- MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 1 - .../Encoder/EncodingJobFactory.cs | 23 ----- .../MediaBrowser.Model.Portable.csproj | 3 - .../MediaBrowser.Model.net35.csproj | 3 - .../Configuration/EncodingOptions.cs | 4 +- .../Configuration/EncodingQuality.cs | 10 --- MediaBrowser.Model/MediaBrowser.Model.csproj | 1 - .../MediaInfo/FFProbeAudioInfo.cs | 36 ++++---- 10 files changed, 37 insertions(+), 185 deletions(-) delete mode 100644 MediaBrowser.Model/Configuration/EncodingQuality.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 3cc04333a..3bef397f9 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -263,38 +263,27 @@ namespace MediaBrowser.Api.Playback return returnFirstIfNoIndex ? streams.FirstOrDefault() : null; } - protected EncodingQuality GetQualitySetting() - { - var quality = ApiEntryPoint.Instance.GetEncodingOptions().EncodingQuality; - - if (quality == EncodingQuality.Auto) - { - var cpuCount = Environment.ProcessorCount; - - if (cpuCount >= 4) - { - //return EncodingQuality.HighQuality; - } - - return EncodingQuality.HighSpeed; - } - - return quality; - } - /// <summary> /// Gets the number of threads. /// </summary> /// <returns>System.Int32.</returns> protected int GetNumberOfThreads(StreamState state, bool isWebm) { + var threads = ApiEntryPoint.Instance.GetEncodingOptions().EncodingThreadCount; + if (isWebm) { // Recommended per docs return Math.Max(Environment.ProcessorCount - 1, 2); } - return 0; + // Automatic + if (threads == -1) + { + return 0; + } + + return threads; } protected string H264Encoder @@ -326,77 +315,31 @@ namespace MediaBrowser.Api.Playback var isVc1 = state.VideoStream != null && string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase); - var qualitySetting = GetQualitySetting(); - if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { param = "-preset superfast"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param += " -crf 23"; - break; - case EncodingQuality.HighQuality: - param += " -crf 20"; - break; - case EncodingQuality.MaxQuality: - param += " -crf 18"; - break; - } + param += " -crf 23"; } else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) { param = "-preset fast"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param += " -crf 28"; - break; - case EncodingQuality.HighQuality: - param += " -crf 25"; - break; - case EncodingQuality.MaxQuality: - param += " -crf 21"; - break; - } + param += " -crf 28"; } // h264 (h264_qsv) else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param = "-preset 7"; - break; - case EncodingQuality.HighQuality: - param = "-preset 4"; - break; - case EncodingQuality.MaxQuality: - param = "-preset 1"; - break; - } + param = "-preset 7"; } // h264 (libnvenc) else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase)) { - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param = "-preset high-performance"; - break; - case EncodingQuality.HighQuality: - param = ""; - break; - case EncodingQuality.MaxQuality: - param = "-preset high-quality"; - break; - } + param = "-preset high-performance"; } // webm @@ -409,20 +352,7 @@ namespace MediaBrowser.Api.Playback var qmin = "0"; var qmax = "50"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - crf = "10"; - break; - case EncodingQuality.HighQuality: - crf = "6"; - break; - case EncodingQuality.MaxQuality: - crf = "4"; - break; - default: - throw new ArgumentException("Unrecognized quality setting"); - } + crf = "10"; if (isVc1) { diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 9153045e6..140e84963 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -521,42 +521,18 @@ namespace MediaBrowser.MediaEncoding.Encoder var isVc1 = state.VideoStream != null && string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase); - var qualitySetting = state.Quality; - if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { param = "-preset superfast"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param += " -crf 28"; - break; - case EncodingQuality.HighQuality: - param += " -crf 25"; - break; - case EncodingQuality.MaxQuality: - param += " -crf 21"; - break; - } + param += " -crf 28"; } else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) { param = "-preset fast"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - param += " -crf 28"; - break; - case EncodingQuality.HighQuality: - param += " -crf 25"; - break; - case EncodingQuality.MaxQuality: - param += " -crf 21"; - break; - } + param += " -crf 28"; } // webm @@ -569,20 +545,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var qmin = "0"; var qmax = "50"; - switch (qualitySetting) - { - case EncodingQuality.HighSpeed: - crf = "10"; - break; - case EncodingQuality.HighQuality: - crf = "6"; - break; - case EncodingQuality.MaxQuality: - crf = "4"; - break; - default: - throw new ArgumentException("Unrecognized quality setting"); - } + crf = "10"; if (isVc1) { diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index bb32ac95b..2eeb580e3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -25,7 +25,6 @@ namespace MediaBrowser.MediaEncoding.Encoder public Stream LogFileStream { get; set; } public IProgress<double> Progress { get; set; } public TaskCompletionSource<bool> TaskCompletionSource; - public EncodingQuality Quality { get; set; } public EncodingJobOptions Options { get; set; } public string InputContainer { get; set; } public MediaSourceInfo MediaSource { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index d56838c8b..476d9166b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -96,10 +96,6 @@ namespace MediaBrowser.MediaEncoding.Encoder TryStreamCopy(state, request); - state.Quality = options.Context == EncodingContext.Static ? - EncodingQuality.MaxQuality : - GetQualitySetting(); - return state; } @@ -199,25 +195,6 @@ namespace MediaBrowser.MediaEncoding.Encoder state.MediaSource = mediaSource; } - protected EncodingQuality GetQualitySetting() - { - var quality = GetEncodingOptions().EncodingQuality; - - if (quality == EncodingQuality.Auto) - { - var cpuCount = Environment.ProcessorCount; - - if (cpuCount >= 4) - { - //return EncodingQuality.HighQuality; - } - - return EncodingQuality.HighSpeed; - } - - return quality; - } - protected EncodingOptions GetEncodingOptions() { return _config.GetConfiguration<EncodingOptions>("encoding"); diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 90a185a97..7d813e903 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -203,9 +203,6 @@ <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs"> <Link>Configuration\EncodingOptions.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs"> - <Link>Configuration\EncodingQuality.cs</Link> - </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\FanartOptions.cs"> <Link>Configuration\FanartOptions.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index e7878fb1b..8605a0ab3 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -168,9 +168,6 @@ <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs"> <Link>Configuration\EncodingOptions.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs"> - <Link>Configuration\EncodingQuality.cs</Link> - </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\FanartOptions.cs"> <Link>Configuration\FanartOptions.cs</Link> </Compile> diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index ae714a84e..6d3894f02 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -3,7 +3,7 @@ namespace MediaBrowser.Model.Configuration { public class EncodingOptions { - public EncodingQuality EncodingQuality { get; set; } + public int EncodingThreadCount { get; set; } public string TranscodingTempPath { get; set; } public double DownMixAudioBoost { get; set; } public string H264Encoder { get; set; } @@ -15,9 +15,9 @@ namespace MediaBrowser.Model.Configuration { H264Encoder = "libx264"; DownMixAudioBoost = 2; - EncodingQuality = EncodingQuality.Auto; EnableThrottling = true; ThrottleThresholdInSeconds = 120; + EncodingThreadCount = -1; } } } diff --git a/MediaBrowser.Model/Configuration/EncodingQuality.cs b/MediaBrowser.Model/Configuration/EncodingQuality.cs deleted file mode 100644 index ba5a1f279..000000000 --- a/MediaBrowser.Model/Configuration/EncodingQuality.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace MediaBrowser.Model.Configuration -{ - public enum EncodingQuality - { - Auto, - HighSpeed, - HighQuality, - MaxQuality - } -} \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 5c7caf407..19c5c833a 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -159,7 +159,6 @@ <Compile Include="FileOrganization\TvFileOrganizationOptions.cs" /> <Compile Include="Configuration\BaseApplicationConfiguration.cs" /> <Compile Include="Configuration\DlnaOptions.cs" /> - <Compile Include="Configuration\EncodingQuality.cs" /> <Compile Include="Configuration\ImageOption.cs" /> <Compile Include="Configuration\ImageSavingConvention.cs" /> <Compile Include="LiveTv\LiveTvOptions.cs" /> diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index f2f1663e4..0d4fc6720 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -61,22 +61,22 @@ namespace MediaBrowser.Providers.MediaInfo { cancellationToken.ThrowIfCancellationRequested(); - var idString = item.Id.ToString("N"); - var cachePath = Path.Combine(_appPaths.CachePath, - "ffprobe-audio", - idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); - - try - { - return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath); - } - catch (FileNotFoundException) - { - - } - catch (DirectoryNotFoundException) - { - } + //var idString = item.Id.ToString("N"); + //var cachePath = Path.Combine(_appPaths.CachePath, + // "ffprobe-audio", + // idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); + + //try + //{ + // return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath); + //} + //catch (FileNotFoundException) + //{ + + //} + //catch (DirectoryNotFoundException) + //{ + //} var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest { @@ -86,8 +86,8 @@ namespace MediaBrowser.Providers.MediaInfo }, cancellationToken).ConfigureAwait(false); - Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); - _json.SerializeToFile(result, cachePath); + //Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); + //_json.SerializeToFile(result, cachePath); return result; } -- cgit v1.2.3 From 25395c5d82a9136253706a7fed5a552dcc452acd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 30 Jul 2015 22:34:15 -0400 Subject: update stream builder subtitles --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 7 ++++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 0f99da8b4..e0cc1b705 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -735,7 +735,12 @@ namespace MediaBrowser.Model.Dlna continue; } - if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format)) + if (profile.Method != SubtitleDeliveryMethod.Embed) + { + continue; + } + + if (subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format) && StringHelper.EqualsIgnoreCase(profile.Format, subtitleStream.Codec)) { return profile; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index 10baffea6..c74220137 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun string location; if (e.Headers.TryGetValue("Location", out location)) { - _logger.Debug("HdHomerun found at {0}", location); + //_logger.Debug("HdHomerun found at {0}", location); // Just get the beginning of the url Uri uri; @@ -50,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun var apiUrl = location.Replace(uri.LocalPath, String.Empty, StringComparison.OrdinalIgnoreCase) .TrimEnd('/'); - _logger.Debug("HdHomerun api url: {0}", apiUrl); + //_logger.Debug("HdHomerun api url: {0}", apiUrl); AddDevice(apiUrl); } } -- cgit v1.2.3 From edecae6ed5bcd7159ac2ba2c12d8d38824915129 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 2 Aug 2015 13:02:23 -0400 Subject: improve guide loading performance --- Emby.Drawing/ImageProcessor.cs | 26 +++---- MediaBrowser.Api/LiveTv/LiveTvService.cs | 80 +++++++++++++++++++--- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 15 ++-- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 18 ++--- MediaBrowser.Model/Channels/ChannelQuery.cs | 14 +++- MediaBrowser.Model/LiveTv/ProgramQuery.cs | 10 +++ .../LiveTv/RecommendedProgramQuery.cs | 14 +++- MediaBrowser.Model/LiveTv/RecordingQuery.cs | 14 +++- .../Dto/DtoService.cs | 5 -- .../Library/MediaSourceManager.cs | 4 ++ .../LiveTv/LiveTvDtoService.cs | 5 +- .../LiveTv/LiveTvManager.cs | 14 ++-- 12 files changed, 166 insertions(+), 53 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 2ba4f5aab..1e4537bae 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -410,18 +410,20 @@ namespace Emby.Drawing { ImageSize size; - try - { - size = ImageHeader.GetDimensions(path, _logger, _fileSystem); - } - catch - { - _logger.Info("Failed to read image header for {0}. Doing it the slow way.", path); - - CheckDisposed(); - - size = _imageEncoder.GetImageSize(path); - } + size = ImageHeader.GetDimensions(path, _logger, _fileSystem); + //try + //{ + // size = ImageHeader.GetDimensions(path, _logger, _fileSystem); + //} + //catch + //{ + // return; + // //_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path); + + // //CheckDisposed(); + + // //size = _imageEncoder.GetImageSize(path); + //} StartSaveImageSizeTimer(); diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 6814ad751..3ff4c4828 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")] [Authenticated] - public class GetChannels : IReturn<QueryResult<ChannelInfoDto>> + public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>, IHasDtoOptions { [ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public ChannelType? Type { get; set; } @@ -62,6 +62,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableFavoriteSorting", Description = "Incorporate favorite and like status into channel sorting.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableFavoriteSorting { 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; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")] @@ -81,7 +97,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")] [Authenticated] - public class GetRecordings : IReturn<QueryResult<BaseItemDto>> + public class GetRecordings : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string ChannelId { get; set; } @@ -106,6 +122,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string SeriesTimerId { 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; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")] @@ -164,7 +196,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] [Authenticated] - public class GetPrograms : IReturn<QueryResult<BaseItemDto>> + public class GetPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string ChannelIds { get; set; } @@ -207,11 +239,27 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string Genres { 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; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] [Authenticated] - public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>> + public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string UserId { get; set; } @@ -230,6 +278,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMovie { 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; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")] @@ -490,7 +554,7 @@ namespace MediaBrowser.Api.LiveTv IsDisliked = request.IsDisliked, EnableFavoriteSorting = request.EnableFavoriteSorting - }, CancellationToken.None).ConfigureAwait(false); + }, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } @@ -546,7 +610,7 @@ namespace MediaBrowser.Api.LiveTv query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false); + var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -563,7 +627,7 @@ namespace MediaBrowser.Api.LiveTv IsSports = request.IsSports }; - var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false); + var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -575,7 +639,7 @@ namespace MediaBrowser.Api.LiveTv public async Task<object> Get(GetRecordings request) { - var options = new DtoOptions(); + var options = GetDtoOptions(request); options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; var result = await _liveTvManager.GetRecordings(new RecordingQuery diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 53ad6dbdc..889875383 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -69,9 +69,10 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the channels. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>IEnumerable{Channel}.</returns> - Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken); + Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recording. @@ -173,14 +174,15 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="user">The user.</param> /// <returns>Task{ProgramInfoDto}.</returns> Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null); - + /// <summary> /// Gets the programs. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>IEnumerable{ProgramInfo}.</returns> - Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken); + Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Updates the timer. @@ -240,10 +242,10 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the recommended programs. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns> - Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, - CancellationToken cancellationToken); + Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recommended programs internal. @@ -251,8 +253,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="query">The query.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<QueryResult<LiveTvProgram>>.</returns> - Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, - CancellationToken cancellationToken); + Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken); /// <summary> /// Gets the live tv information. diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 0e4cf7392..25514f1dc 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -971,17 +971,17 @@ namespace MediaBrowser.Dlna.Didl int? width = null; int? height = null; - try - { - var size = _imageProcessor.GetImageSize(imageInfo); + //try + //{ + // var size = _imageProcessor.GetImageSize(imageInfo); - width = Convert.ToInt32(size.Width); - height = Convert.ToInt32(size.Height); - } - catch - { + // width = Convert.ToInt32(size.Width); + // height = Convert.ToInt32(size.Height); + //} + //catch + //{ - } + //} return new ImageDownloadInfo { diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs index 3c6e43fde..b63d797f4 100644 --- a/MediaBrowser.Model/Channels/ChannelQuery.cs +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -1,7 +1,19 @@ -namespace MediaBrowser.Model.Channels +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.Channels { public class ChannelQuery { + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the user identifier. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index c19ba54bd..3f652ea6f 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Entities; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Model.LiveTv { @@ -15,6 +16,15 @@ namespace MediaBrowser.Model.LiveTv Genres = new string[] { }; } + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the channel ids. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 4a8ae2365..09d45066b 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -1,7 +1,19 @@ -namespace MediaBrowser.Model.LiveTv +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.LiveTv { public class RecommendedProgramQuery { + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the user identifier. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index daa137db6..0cf997602 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -1,4 +1,7 @@ -namespace MediaBrowser.Model.LiveTv +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.LiveTv { /// <summary> /// Class RecordingQuery. @@ -58,5 +61,14 @@ /// </summary> /// <value>The series timer identifier.</value> public string SeriesTimerId { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 31f1b17dd..2ff9a2813 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1767,11 +1767,6 @@ namespace MediaBrowser.Server.Implementations.Dto { size = _imageProcessor.GetImageSize(imageInfo); } - catch (FileNotFoundException) - { - _logger.Error("Image file does not exist: {0}", path); - return; - } catch (Exception ex) { _logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path); diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 87e71e327..2263b3e1f 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -77,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library { return false; } + if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase)) + { + return false; + } return true; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 72fea2c79..9ffd8a500 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -198,10 +198,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv /// Gets the channel info dto. /// </summary> /// <param name="info">The info.</param> + /// <param name="options">The options.</param> /// <param name="currentProgram">The current program.</param> /// <param name="user">The user.</param> /// <returns>ChannelInfoDto.</returns> - public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, LiveTvProgram currentProgram, User user = null) + public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, DtoOptions options, LiveTvProgram currentProgram, User user = null) { var dto = new ChannelInfoDto { @@ -238,7 +239,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (currentProgram != null) { - dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, new DtoOptions(), user); + dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user); } return dto; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d8954724a..f73e648fa 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -238,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return result; } - public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -261,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channelIdString = channel.Id.ToString("N"); var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString, StringComparison.OrdinalIgnoreCase)); - returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user)); + returnList.Add(_tvDtoService.GetChannelInfoDto(channel, options, currentProgram, user)); } var result = new QueryResult<ChannelInfoDto> @@ -762,7 +762,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return dto; } - public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var internalQuery = new InternalItemsQuery { @@ -822,7 +822,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Select(i => { RefreshIfNeeded(i); - return _dtoService.GetBaseItemDto(i, new DtoOptions(), user); + return _dtoService.GetBaseItemDto(i, options, user); }) .ToArray(); @@ -907,14 +907,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv return result; } - public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var internalResult = await GetRecommendedProgramsInternal(query, cancellationToken).ConfigureAwait(false); var user = _userManager.GetUserById(query.UserId); var returnArray = internalResult.Items - .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions(), user)) + .Select(i => _dtoService.GetBaseItemDto(i, options, user)) .ToArray(); await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); @@ -1712,7 +1712,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .OrderBy(i => i.StartDate) .FirstOrDefault(); - var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user); + var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user); return dto; } -- cgit v1.2.3 From 47b1a4cafd0cc1882503e46fb8a5082a3b061078 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 2 Aug 2015 15:08:55 -0400 Subject: update image processing --- Emby.Drawing/ImageProcessor.cs | 16 +++++++++++++++- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- MediaBrowser.Api/Playback/StreamState.cs | 2 +- MediaBrowser.Api/StartupWizardService.cs | 1 + MediaBrowser.Controller/Library/IMetadataFileSaver.cs | 5 +++++ MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs | 9 +++++++-- MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs | 9 +++++++-- MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs | 9 +++++++-- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 +- MediaBrowser.Model/Configuration/ServerConfiguration.cs | 2 ++ MediaBrowser.Model/Dto/MediaSourceInfo.cs | 4 ++-- MediaBrowser.Providers/Manager/ProviderManager.cs | 8 +++++++- .../Library/MediaSourceManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 4 ++-- .../LiveTv/LiveTvMediaSourceProvider.cs | 8 ++++++-- Nuget/MediaBrowser.Common.Internal.nuspec | 4 ++-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 ++-- 20 files changed, 72 insertions(+), 25 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 1e4537bae..9db2c1c20 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -189,7 +189,21 @@ namespace Emby.Drawing dateModified = tuple.Item2; } - var originalImageSize = GetImageSize(originalImagePath, dateModified); + ImageSize originalImageSize; + + try + { + originalImageSize = GetImageSize(originalImagePath, dateModified); + } + catch + { + // This is an arbitrary default, but don't fail the whole process over this + originalImageSize = new ImageSize + { + Width = 100, + Height = 100 + }; + } // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 3bef397f9..f108b344f 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -854,7 +854,7 @@ namespace MediaBrowser.Api.Playback state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening ?? false) + if (state.MediaSource.RequiresOpening) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 4df696096..34dc5ea12 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Playback private async void DisposeLiveStream() { - if ((MediaSource.RequiresClosing ?? false) && string.IsNullOrWhiteSpace(Request.LiveStreamId)) + if ((MediaSource.RequiresClosing) && string.IsNullOrWhiteSpace(Request.LiveStreamId)) { try { diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 6ee8d3603..277e02bf9 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -67,6 +67,7 @@ namespace MediaBrowser.Api _config.Configuration.EnableLibraryMetadataSubFolder = true; _config.Configuration.EnableUserSpecificUserViews = true; _config.Configuration.EnableCustomPathSubFolders = true; + _config.Configuration.DisableXmlSavers = true; _config.SaveConfiguration(); } diff --git a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs index 0883da48f..e09e58302 100644 --- a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs @@ -11,4 +11,9 @@ namespace MediaBrowser.Controller.Library /// <returns>System.String.</returns> string GetSavePath(IHasMetadata item); } + + public interface IConfigurableProvider + { + bool IsEnabled { get; } + } } \ No newline at end of file diff --git a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs index 7a2a97c0c..96d95d40b 100644 --- a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs @@ -12,7 +12,7 @@ using System.Threading; namespace MediaBrowser.LocalMetadata.Savers { - public class EpisodeXmlSaver : IMetadataFileSaver + public class EpisodeXmlProvider : IMetadataFileSaver, IConfigurableProvider { private readonly IItemRepository _itemRepository; @@ -20,7 +20,7 @@ namespace MediaBrowser.LocalMetadata.Savers private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; - public EpisodeXmlSaver(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager) + public EpisodeXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager) { _itemRepository = itemRepository; _config = config; @@ -51,6 +51,11 @@ namespace MediaBrowser.LocalMetadata.Savers } } + public bool IsEnabled + { + get { return !_config.Configuration.DisableXmlSavers; } + } + /// <summary> /// Saves the specified item. /// </summary> diff --git a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs index dc5b45259..a6fba3e9b 100644 --- a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs @@ -15,13 +15,13 @@ namespace MediaBrowser.LocalMetadata.Savers /// <summary> /// Saves movie.xml for movies, trailers and music videos /// </summary> - public class MovieXmlSaver : IMetadataFileSaver + public class MovieXmlProvider : IMetadataFileSaver, IConfigurableProvider { private readonly IItemRepository _itemRepository; private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; - public MovieXmlSaver(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager) + public MovieXmlProvider(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager) { _itemRepository = itemRepository; _config = config; @@ -36,6 +36,11 @@ namespace MediaBrowser.LocalMetadata.Savers } } + public bool IsEnabled + { + get { return !_config.Configuration.DisableXmlSavers; } + } + /// <summary> /// Determines whether [is enabled for] [the specified item]. /// </summary> diff --git a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs index 45aff5e2c..44b1cd8d3 100644 --- a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs @@ -12,12 +12,12 @@ using System.Threading; namespace MediaBrowser.LocalMetadata.Savers { - public class SeriesXmlSaver : IMetadataFileSaver + public class SeriesXmlProvider : IMetadataFileSaver, IConfigurableProvider { private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; - public SeriesXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager) + public SeriesXmlProvider(IServerConfigurationManager config, ILibraryManager libraryManager) { _config = config; _libraryManager = libraryManager; @@ -47,6 +47,11 @@ namespace MediaBrowser.LocalMetadata.Savers return item is Series && updateType >= ItemUpdateType.MetadataDownload; } + public bool IsEnabled + { + get { return !_config.Configuration.DisableXmlSavers; } + } + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <summary> diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 140e84963..dd88512fb 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -436,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Encoder state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening ?? false) + if (state.MediaSource.RequiresOpening) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index 2eeb580e3..806910d89 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -136,7 +136,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing ?? false) + if (MediaSource.RequiresClosing) { try { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 0a2fabc1b..072416684 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -213,6 +213,8 @@ namespace MediaBrowser.Model.Configuration public int SharingExpirationDays { get; set; } + public bool DisableXmlSavers { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="ServerConfiguration" /> class. /// </summary> diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 75edc6a52..8897edcbd 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Model.Dto public bool SupportsDirectStream { get; set; } public bool SupportsDirectPlay { get; set; } - public bool? RequiresOpening { get; set; } + public bool RequiresOpening { get; set; } public string OpenToken { get; set; } - public bool? RequiresClosing { get; set; } + public bool RequiresClosing { get; set; } public string LiveStreamId { get; set; } public int? BufferMs { get; set; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index beef968fb..453e07987 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -106,9 +106,15 @@ namespace MediaBrowser.Providers.Manager _identityProviders = identityProviders.ToArray(); _identityConverters = identityConverters.ToArray(); _metadataProviders = metadataProviders.ToArray(); - _savers = metadataSavers.ToArray(); _imageSavers = imageSavers.ToArray(); _externalIds = externalIds.OrderBy(i => i.Name).ToArray(); + + _savers = metadataSavers.Where(i => + { + var configurable = i as IConfigurableProvider; + + return configurable == null || configurable.IsEnabled; + }).ToArray(); } public Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 2263b3e1f..c5ff100f9 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -449,7 +449,7 @@ namespace MediaBrowser.Server.Implementations.Library LiveStreamInfo current; if (_openStreams.TryGetValue(id, out current)) { - if (current.MediaSource.RequiresClosing ?? false) + if (current.MediaSource.RequiresClosing) { var tuple = GetProvider(id); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index f73e648fa..b4669f53e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -368,7 +368,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing ?? false) + if (info.RequiresClosing) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; @@ -385,7 +385,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing ?? false) + if (info.RequiresClosing) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index cf34b6b99..66a21830e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -59,6 +59,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv { IEnumerable<MediaSourceInfo> sources; + var forceRequireOpening = false; + try { if (item is ILiveTvRecording) @@ -78,6 +80,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false) .ToList(); + + forceRequireOpening = true; } var list = sources.ToList(); @@ -87,12 +91,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv { source.Type = MediaSourceType.Default; - if (!source.RequiresOpening.HasValue) + if (source.RequiresOpening || forceRequireOpening) { source.RequiresOpening = true; } - if (source.RequiresOpening.HasValue && source.RequiresOpening.Value) + if (source.RequiresOpening) { var openKeys = new List<string>(); openKeys.Add(item.GetType().Name); diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index fffb68e36..c43b90c8c 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.629</version> + <version>3.0.631</version> <title>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 856e63199..32e3b2fc6 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.629 + 3.0.631 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 30175007d..fc33477a9 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.629 + 3.0.631 MediaBrowser.Model - Signed Edition Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index c688c6f2c..704c30f95 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.629 + 3.0.631 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 From 30710dbe007b60d696cdf28e4bf97a428432124b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 4 Aug 2015 10:26:36 -0400 Subject: update components --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 ++++++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + MediaBrowser.Model/LiveTv/ProgramQuery.cs | 5 +++++ MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs | 5 +++++ .../LiveTv/EmbyTV/EmbyTV.cs | 10 +++++----- .../LiveTv/Listings/SchedulesDirect.cs | 15 +++++++-------- .../LiveTv/LiveTvManager.cs | 4 +++- 7 files changed, 34 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 3ff4c4828..bdec55561 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -222,6 +222,9 @@ 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 = "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; } @@ -279,6 +282,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsKids { 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; } @@ -607,6 +613,7 @@ namespace MediaBrowser.Api.LiveTv query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortOrder = request.SortOrder; query.IsMovie = request.IsMovie; + query.IsKids = request.IsKids; query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); @@ -624,6 +631,7 @@ namespace MediaBrowser.Api.LiveTv Limit = request.Limit, HasAired = request.HasAired, IsMovie = request.IsMovie, + IsKids = request.IsKids, IsSports = request.IsSports }; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 7c5d9e9a1..aa68e09a0 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -646,6 +646,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether [supports playlists]. /// /// true if [supports playlists]; otherwise, false. + [IgnoreDataMember] public bool SupportsPlaylists { get diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 3f652ea6f..7a877e356 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -63,6 +63,11 @@ namespace MediaBrowser.Model.LiveTv /// 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. /// diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 09d45066b..e83a8fda6 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -44,6 +44,11 @@ namespace MediaBrowser.Model.LiveTv /// null if [is movie] contains no value, true if [is movie]; otherwise, false. 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. diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9ca2537f1..b96e3b26c 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -490,13 +490,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (recording == null) { - recording = new RecordingInfo() + recording = new RecordingInfo { ChannelId = info.ChannelId, Id = Guid.NewGuid().ToString("N"), StartDate = info.StartDate, EndDate = info.EndDate, - Genres = info.Genres ?? null, + Genres = info.Genres, IsKids = info.IsKids, IsLive = info.IsLive, IsMovie = info.IsMovie, @@ -507,10 +507,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV IsSports = info.IsSports, IsRepeat = !info.IsPremiere, Name = info.Name, - EpisodeTitle = info.EpisodeTitle ?? "", + EpisodeTitle = info.EpisodeTitle, ProgramId = info.Id, - HasImage = info.HasImage ?? false, - ImagePath = info.ImagePath ?? null, + HasImage = info.HasImage, + ImagePath = info.ImagePath, ImageUrl = info.ImageUrl, OriginalAirDate = info.OriginalAirDate, Status = RecordingStatus.Scheduled, diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 655feedae..2aadf4a66 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -286,20 +286,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } ScheduleDirect.Gracenote gracenote; - string EpisodeTitle = ""; + string episodeTitle = null; if (details.metadata != null) { gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; if ((details.showType ?? "No ShowType") == "Series") { - EpisodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; + episodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; } } if (details.episodeTitle150 != null) { - EpisodeTitle = EpisodeTitle + " " + details.episodeTitle150; + episodeTitle = ((episodeTitle ?? string.Empty) + " " + details.episodeTitle150).Trim(); } - bool hasImage = false; + var imageLink = ""; if (details.hasImageArtwork) @@ -314,11 +314,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings Overview = desc, StartDate = startAt, EndDate = endAt, - Genres = new List() { "N/A" }, Name = details.titles[0].title120 ?? "Unkown", OfficialRating = "0", CommunityRating = null, - EpisodeTitle = EpisodeTitle, + EpisodeTitle = episodeTitle, Audio = audioType, IsHD = hdtv, IsRepeat = repeat, @@ -339,8 +338,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings (details.showType ?? "No ShowType") == "Short Film", IsPremiere = false, }; - //logger.Info("Done init"); - if (null != details.originalAirDate) + + if (!string.IsNullOrWhiteSpace(details.originalAirDate)) { info.OriginalAirDate = DateTime.Parse(details.originalAirDate); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index b4669f53e..6861901ac 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -774,6 +774,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ChannelIds = query.ChannelIds, IsMovie = query.IsMovie, IsSports = query.IsSports, + IsKids = query.IsKids, Genres = query.Genres }; @@ -844,7 +845,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, IsAiring = query.IsAiring, IsMovie = query.IsMovie, - IsSports = query.IsSports + IsSports = query.IsSports, + IsKids = query.IsKids }; if (query.HasAired.HasValue) -- cgit v1.2.3 From a59f146965173dd8ec2028826a22a30785c2aa6c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Aug 2015 10:21:29 -0400 Subject: update components --- MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs | 2 -- MediaBrowser.Providers/Music/AudioDbArtistProvider.cs | 4 ++-- MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs | 5 +++++ 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs index ca9db0bf0..1a05f38fa 100644 --- a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs +++ b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs @@ -64,9 +64,7 @@ namespace MediaBrowser.Model.Configuration EnableAutoUpdate = true; LogFileRetentionDays = 3; -#if (DEBUG) EnableDebugLevelLogging = true; -#endif } } } diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index a6dab60b0..eefa1a2f4 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -113,8 +113,6 @@ namespace MediaBrowser.Providers.Music var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, @@ -123,6 +121,8 @@ namespace MediaBrowser.Providers.Music }).ConfigureAwait(false)) { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + using (var xmlFileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { await response.CopyToAsync(xmlFileStream).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 6748c2ba5..70946db36 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -154,6 +154,11 @@ namespace MediaBrowser.Providers.Music result.HasMetadata = true; } + if (!string.IsNullOrEmpty(releaseId) || !string.IsNullOrEmpty(releaseGroupId)) + { + result.HasMetadata = true; + } + if (result.HasMetadata) { if (!string.IsNullOrEmpty(releaseId)) -- cgit v1.2.3 From 1936d6db43e10cc6f45fa72fde4b1628e06b8abd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 10 Aug 2015 13:37:50 -0400 Subject: update search hints --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 5 + MediaBrowser.Api/SearchService.cs | 9 ++ .../Configuration/BaseApplicationConfiguration.cs | 2 - MediaBrowser.Model/Search/SearchHint.cs | 12 ++ .../Library/Resolvers/TV/SeriesResolver.cs | 10 +- .../LiveTv/Listings/Emby/EmbyListings.cs | 59 +++++++++ .../Listings/Emby/EmbyListingsNorthAmerica.cs | 144 +++++++++++++++++++++ .../LiveTv/Listings/Emby/IEmbyListingProvider.cs | 18 +++ .../MediaBrowser.Server.Implementations.csproj | 3 + .../ApplicationHost.cs | 21 ++- .../MediaBrowser.WebDashboard.csproj | 6 + 11 files changed, 276 insertions(+), 13 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f108b344f..8f5301642 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1748,6 +1748,11 @@ namespace MediaBrowser.Api.Playback return false; } + if (videoStream.IsAnamorphic ?? false) + { + return false; + } + // Can't stream copy if we're burning in subtitles if (request.SubtitleStreamIndex.HasValue) { diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 9d1aef300..302b8d834 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; @@ -171,6 +172,8 @@ namespace MediaBrowser.Api ProductionYear = item.ProductionYear }; + result.ChannelId = item.ChannelId; + var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); if (primaryImageTag != null) @@ -218,6 +221,12 @@ namespace MediaBrowser.Api result.Artists = song.Artists.ToArray(); } + if (!string.IsNullOrWhiteSpace(item.ChannelId)) + { + var channel = _libraryManager.GetItemById(item.ChannelId); + result.ChannelName = channel == null ? null : channel.Name; + } + return result; } diff --git a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs index 1a05f38fa..2b53c6688 100644 --- a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs +++ b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs @@ -63,8 +63,6 @@ namespace MediaBrowser.Model.Configuration { EnableAutoUpdate = true; LogFileRetentionDays = 3; - - EnableDebugLevelLogging = true; } } } diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index 4eced7706..d51c0325d 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -132,5 +132,17 @@ namespace MediaBrowser.Model.Search /// /// The episode count. public int? EpisodeCount { get; set; } + + /// + /// Gets or sets the channel identifier. + /// + /// The channel identifier. + public string ChannelId { get; set; } + + /// + /// Gets or sets the name of the channel. + /// + /// The name of the channel. + public string ChannelName { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index f12022dc7..c5565eb53 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -110,11 +110,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { var attributes = child.Attributes; - if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) - { - //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName); - continue; - } + //if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) + //{ + // //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName); + // continue; + //} // Can't enforce this because files saved by Bitcasa are always marked System //if ((attributes & FileAttributes.System) == FileAttributes.System) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs new file mode 100644 index 000000000..5edebb393 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs @@ -0,0 +1,59 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Serialization; + +namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby +{ + public class EmbyGuide : IListingsProvider + { + private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _jsonSerializer; + + public EmbyGuide(IHttpClient httpClient, IJsonSerializer jsonSerializer) + { + _httpClient = httpClient; + _jsonSerializer = jsonSerializer; + } + + public string Name + { + get { return "Emby Guide"; } + } + + public string Type + { + get { return "emby"; } + } + + public Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + return GetListingsProvider(info.Country).GetProgramsAsync(info, channelNumber, startDateUtc, endDateUtc, cancellationToken); + } + + public Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken) + { + return GetListingsProvider(info.Country).AddMetadata(info, channels, cancellationToken); + } + + public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) + { + return GetListingsProvider(info.Country).Validate(info, validateLogin, validateListings); + } + + public Task> GetLineups(ListingsProviderInfo info, string country, string location) + { + return GetListingsProvider(country).GetLineups(info, country, location); + } + + private IEmbyListingProvider GetListingsProvider(string country) + { + return new EmbyListingsNorthAmerica(_httpClient, _jsonSerializer); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs new file mode 100644 index 000000000..99bd5325e --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs @@ -0,0 +1,144 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby +{ + public class EmbyListingsNorthAmerica : IEmbyListingProvider + { + private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _jsonSerializer; + + public EmbyListingsNorthAmerica(IHttpClient httpClient, IJsonSerializer jsonSerializer) + { + _httpClient = httpClient; + _jsonSerializer = jsonSerializer; + } + + public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + return new List(); + } + + public async Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken) + { + var response = await GetResponse("https://data.emby.media/service/lineups?id=" + info.ListingsId).ConfigureAwait(false); + + foreach (var channel in channels) + { + + } + } + + public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) + { + return Task.FromResult(true); + } + + public async Task> GetLineups(ListingsProviderInfo info, string country, string location) + { + var response = await GetResponse("https://data.emby.media/service/lineups?id=" + location).ConfigureAwait(false); + + return response.Select(i => new NameIdPair + { + + Name = GetName(i), + Id = i.lineupID + + }).ToList(); + } + + private string GetName(LineupInfo info) + { + var name = info.lineupName; + + if (string.Equals(info.lineupType, "cab", StringComparison.OrdinalIgnoreCase)) + { + name += " - Cable"; + } + else if (string.Equals(info.lineupType, "sat", StringComparison.OrdinalIgnoreCase)) + { + name += " - SAT"; + } + else if (string.Equals(info.lineupType, "ota", StringComparison.OrdinalIgnoreCase)) + { + name += " - OTA"; + } + + return name; + } + + private async Task GetResponse(string url) + where T : class + { + using (var stream = await _httpClient.Get(new HttpRequestOptions + { + Url = url + + }).ConfigureAwait(false)) + { + using (var reader = new StreamReader(stream)) + { + var path = await reader.ReadToEndAsync().ConfigureAwait(false); + + // location = zip code + using (var secondStream = await _httpClient.Get(new HttpRequestOptions + { + Url = "https://data.emby.media" + path + + }).ConfigureAwait(false)) + { + return _jsonSerializer.DeserializeFromStream(secondStream); + } + } + } + } + + private class LineupInfo + { + public string lineupID { get; set; } + public string lineupName { get; set; } + public string lineupType { get; set; } + public string providerID { get; set; } + public string providerName { get; set; } + public string serviceArea { get; set; } + public string country { get; set; } + } + + private class Station + { + public string number { get; set; } + public int channelNumber { get; set; } + public int subChannelNumber { get; set; } + public int stationID { get; set; } + public string name { get; set; } + public string callsign { get; set; } + public string network { get; set; } + public string stationType { get; set; } + public int NTSC_TSID { get; set; } + public int DTV_TSID { get; set; } + public string webLink { get; set; } + public string logoFilename { get; set; } + } + + private class LineupDetailResponse + { + public string lineupID { get; set; } + public string lineupName { get; set; } + public string lineupType { get; set; } + public string providerID { get; set; } + public string providerName { get; set; } + public string serviceArea { get; set; } + public string country { get; set; } + public List stations { get; set; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs new file mode 100644 index 000000000..83477acfc --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs @@ -0,0 +1,18 @@ +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby +{ + public interface IEmbyListingProvider + { + Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken); + Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings); + Task> GetLineups(ListingsProviderInfo info, string country, string location); + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 7eddf5ed1..2571f9b2c 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -222,6 +222,9 @@ + + + diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index b554e0d1c..60ff36c6d 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -529,7 +529,7 @@ namespace MediaBrowser.Server.Startup.Common var sharingRepo = new SharingRepository(LogManager, ApplicationPaths); await sharingRepo.Initialize().ConfigureAwait(false); RegisterSingleInstance(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this)); - + RegisterSingleInstance(new SsdpHandler(LogManager.GetLogger("SsdpHandler"), ServerConfigurationManager, this)); var activityLogRepo = await GetActivityLogRepository().ConfigureAwait(false); @@ -1088,15 +1088,24 @@ namespace MediaBrowser.Server.Startup.Common { get { - // Return the first matched address, if found, or the first known local address - var address = LocalIpAddress; + try + { + // Return the first matched address, if found, or the first known local address + var address = LocalIpAddress; - if (!string.IsNullOrWhiteSpace(address)) + if (!string.IsNullOrWhiteSpace(address)) + { + address = GetLocalApiUrl(address); + } + + return address; + } + catch (Exception ex) { - address = GetLocalApiUrl(address); + Logger.ErrorException("Error getting local Ip address information", ex); } - return address; + return null; } } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index a1e232257..e8a2e8673 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -183,6 +183,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -213,6 +216,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest -- cgit v1.2.3 From 9c879eefc33df13b7dac555e159d5c4ccf09213e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 14 Aug 2015 15:14:54 -0400 Subject: update channel settings --- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 +-- MediaBrowser.Model/Configuration/UserConfiguration.cs | 1 + MediaBrowser.Server.Implementations/Library/LibraryManager.cs | 2 +- MediaBrowser.Server.Implementations/Library/UserViewManager.cs | 5 ++--- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index e568b2eae..df09d39b2 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -273,10 +273,9 @@ namespace MediaBrowser.Controller.LiveTv /// /// Gets the live tv folder. /// - /// The user identifier. /// The cancellation token. /// BaseItemDto. - Task GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken); + Task GetInternalLiveTvFolder(CancellationToken cancellationToken); /// /// Gets the live tv folder. diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 9dd84bc7d..349780958 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -50,6 +50,7 @@ namespace MediaBrowser.Model.Configuration public string[] PlainFolderViews { get; set; } public bool HidePlayedInLatest { get; set; } + public bool DisplayChannelsInline { get; set; } /// /// Initializes a new instance of the class. diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index c316aab25..0cfd38479 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1824,7 +1824,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } - var idValues = "37_namedview_" + name + (parentId ?? string.Empty); + var idValues = "37_namedview_" + name + (parentId ?? string.Empty) + (viewType ?? string.Empty); if (!string.IsNullOrWhiteSpace(uniqueId)) { idValues += uniqueId; diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 5d753826a..a609c53ab 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -156,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.Library var channels = channelResult.Items; var embeddedChannels = channels - .Where(i => user.Configuration.DisplayChannelsWithinViews.Contains(i.Id.ToString("N"))) + .Where(i => user.Configuration.DisplayChannelsInline || user.Configuration.DisplayChannelsWithinViews.Contains(i.Id.ToString("N"))) .ToList(); list.AddRange(embeddedChannels); @@ -168,8 +168,7 @@ namespace MediaBrowser.Server.Implementations.Library if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) { - var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.LiveTv); - list.Add(await _libraryManager.GetNamedView(name, CollectionType.LiveTv, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await _liveTvManager.GetInternalLiveTvFolder(CancellationToken.None).ConfigureAwait(false)); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index cc3c06dd4..782473bea 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2196,15 +2196,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId); - var folder = await GetInternalLiveTvFolder(userId, cancellationToken).ConfigureAwait(false); + var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user); } - public async Task GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken) + public async Task GetInternalLiveTvFolder(CancellationToken cancellationToken) { var name = _localization.GetLocalizedString("ViewTypeLiveTV"); - return await _libraryManager.GetNamedView(name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); + return await _libraryManager.GetNamedView(name, "livetv", name, cancellationToken).ConfigureAwait(false); } public async Task SaveTunerHost(TunerHostInfo info) -- cgit v1.2.3 From 54dd38b2bd3457592b2137baabb34ea2ced1f661 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 14 Aug 2015 21:44:30 -0400 Subject: revise shortcut support --- .../Entities/CollectionFolder.cs | 9 +++ MediaBrowser.Controller/Entities/Folder.cs | 66 ++++++++++++---------- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 9 +++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 13 ++++- .../Configuration/ServerConfiguration.cs | 1 + 5 files changed, 66 insertions(+), 32 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 3a610be64..8821f35c8 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + protected override bool SupportsShortcutChildren + { + get + { + return true; + } + } + public override bool CanDelete() { return false; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 22efb09e1..c3ac77328 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,7 +1,6 @@ using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -14,7 +13,6 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -50,7 +48,7 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public virtual bool IsPreSorted { - get { return false; } + get { return ConfigurationManager.Configuration.EnableWindowsShortcuts; } } /// @@ -122,7 +120,7 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] protected virtual bool SupportsShortcutChildren { - get { return true; } + get { return false; } } /// @@ -176,7 +174,7 @@ namespace MediaBrowser.Controller.Entities protected void AddChildInternal(BaseItem child) { var actualChildren = ActualChildren; - + lock (_childrenSyncLock) { var newChildren = actualChildren.ToList(); @@ -1070,7 +1068,7 @@ namespace MediaBrowser.Controller.Entities { var changesFound = false; - if (SupportsShortcutChildren && LocationType == LocationType.FileSystem) + if (LocationType == LocationType.FileSystem) { if (RefreshLinkedChildren(fileSystemChildren)) { @@ -1092,37 +1090,43 @@ namespace MediaBrowser.Controller.Entities var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList(); var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList(); - var newShortcutLinks = fileSystemChildren - .Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName)) - .Select(i => - { - try + List newShortcutLinks; + + if (SupportsShortcutChildren) + { + newShortcutLinks = fileSystemChildren + .Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName)) + .Select(i => { - Logger.Debug("Found shortcut at {0}", i.FullName); + try + { + Logger.Debug("Found shortcut at {0}", i.FullName); - var resolvedPath = FileSystem.ResolveShortcut(i.FullName); + var resolvedPath = FileSystem.ResolveShortcut(i.FullName); - if (!string.IsNullOrEmpty(resolvedPath)) - { - return new LinkedChild + if (!string.IsNullOrEmpty(resolvedPath)) { - Path = resolvedPath, - Type = LinkedChildType.Shortcut - }; - } + return new LinkedChild + { + Path = resolvedPath, + Type = LinkedChildType.Shortcut + }; + } - Logger.Error("Error resolving shortcut {0}", i.FullName); + Logger.Error("Error resolving shortcut {0}", i.FullName); - return null; - } - catch (IOException ex) - { - Logger.ErrorException("Error resolving shortcut {0}", ex, i.FullName); - return null; - } - }) - .Where(i => i != null) - .ToList(); + return null; + } + catch (IOException ex) + { + Logger.ErrorException("Error resolving shortcut {0}", ex, i.FullName); + return null; + } + }) + .Where(i => i != null) + .ToList(); + } + else { newShortcutLinks = new List(); } if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer())) { diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 02e9d4cf9..9317f688f 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -74,6 +74,15 @@ namespace MediaBrowser.Controller.Entities.Movies } } + [IgnoreDataMember] + protected override bool SupportsShortcutChildren + { + get + { + return true; + } + } + public override bool IsAuthorizedToDelete(User user) { return true; diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index b065ae171..a78beb645 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Providers; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; @@ -36,6 +37,16 @@ namespace MediaBrowser.Controller.Entities return PostFilterAndSort(result.Where(filter), query); } + [IgnoreDataMember] + protected override bool SupportsShortcutChildren + { + get + { + return true; + } + } + + [IgnoreDataMember] public override bool IsPreSorted { get diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 072416684..46f9db580 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -214,6 +214,7 @@ namespace MediaBrowser.Model.Configuration public int SharingExpirationDays { get; set; } public bool DisableXmlSavers { get; set; } + public bool EnableWindowsShortcuts { get; set; } /// /// Initializes a new instance of the class. -- cgit v1.2.3 From 1f1f7642c3df2f9ec67bbdbdb4d5ed66e126f3ab Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 16 Aug 2015 11:53:30 -0400 Subject: update subtitle escaping --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 ++-- MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 7 +++++++ MediaBrowser.Controller/Session/SessionInfo.cs | 6 ++++++ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 4 ++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 5 +++++ MediaBrowser.Model/Session/SessionInfoDto.cs | 6 ++++++ .../Session/SessionManager.cs | 2 ++ .../MediaBrowser.WebDashboard.csproj | 17 +++-------------- 8 files changed, 33 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 8f5301642..6fba6052f 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -619,7 +619,7 @@ namespace MediaBrowser.Api.Playback // TODO: Perhaps also use original_size=1920x800 ?? return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB", - subtitlePath.Replace('\\', '/').Replace(":/", "\\:/"), + MediaEncoder.EscapeSubtitleFilterPath(subtitlePath), charsetParam, seconds.ToString(UsCulture)); } @@ -627,7 +627,7 @@ namespace MediaBrowser.Api.Playback var mediaPath = state.MediaPath ?? string.Empty; return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB", - mediaPath.Replace('\\', '/').Replace(":/", "\\:/"), + MediaEncoder.EscapeSubtitleFilterPath(mediaPath), state.InternalSubtitleStreamOffset.ToString(UsCulture), seconds.ToString(UsCulture)); } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 5bec7980a..23285b612 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -116,5 +116,12 @@ namespace MediaBrowser.Controller.MediaEncoding Task EncodeVideo(EncodingJobOptions options, IProgress progress, CancellationToken cancellationToken); + + /// + /// Escapes the subtitle filter path. + /// + /// The path. + /// System.String. + string EscapeSubtitleFilterPath(string path); } } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 64b20c13e..b3e82f925 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -125,6 +125,12 @@ namespace MediaBrowser.Controller.Session /// The session controller. public ISessionController SessionController { get; set; } + /// + /// Gets or sets the application icon URL. + /// + /// The application icon URL. + public string AppIconUrl { get; set; } + /// /// Gets or sets the supported commands. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index dd88512fb..181f147b4 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -865,13 +865,13 @@ namespace MediaBrowser.MediaEncoding.Encoder // TODO: Perhaps also use original_size=1920x800 ?? return string.Format("subtitles=filename='{0}'{1},setpts=PTS -{2}/TB", - subtitlePath.Replace('\\', '/').Replace(":/", "\\:/"), + MediaEncoder.EscapeSubtitleFilterPath(subtitlePath), charsetParam, seconds.ToString(UsCulture)); } return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB", - state.MediaPath.Replace('\\', '/').Replace(":/", "\\:/"), + MediaEncoder.EscapeSubtitleFilterPath(state.MediaPath), state.InternalSubtitleStreamOffset.ToString(UsCulture), seconds.ToString(UsCulture)); } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c059a8b54..50b6a94aa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -765,6 +765,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public string EscapeSubtitleFilterPath(string path) + { + return path.Replace('\\', '/').Replace(":/", "\\:/").Replace("'", "'\\\\\\'"); + } + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index 98df3efe5..da8ab9b8a 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -99,6 +99,12 @@ namespace MediaBrowser.Model.Session /// /// The device id. public string DeviceId { get; set; } + + /// + /// Gets or sets the application icon URL. + /// + /// The application icon URL. + public string AppIconUrl { get; set; } /// /// Gets or sets a value indicating whether [supports remote control]. diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index c2160f48a..70a4cb439 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -161,6 +161,7 @@ namespace MediaBrowser.Server.Implementations.Session if (capabilities != null) { + info.AppIconUrl = capabilities.IconUrl; ReportCapabilities(info, capabilities, false); } } @@ -1476,6 +1477,7 @@ namespace MediaBrowser.Server.Implementations.Session NowPlayingItem = session.NowPlayingItem, SupportsRemoteControl = session.SupportsMediaControl, PlayState = session.PlayState, + AppIconUrl = session.AppIconUrl, TranscodingInfo = session.NowPlayingItem == null ? null : session.TranscodingInfo }; diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 42a9c5c1b..a90fbaec8 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -156,6 +156,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -565,12 +568,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -802,9 +799,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -2207,11 +2201,6 @@ PreserveNewest - - - PreserveNewest - - PreserveNewest -- cgit v1.2.3 From f49417c703802a646910476dab38dc3f1adfb5c3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 16 Aug 2015 16:26:49 -0400 Subject: update series recordings --- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 ++++++ MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs | 9 +++++++++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs | 6 ++++-- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 5 ++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 ++ 6 files changed, 26 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index b54a7aaee..0a1735c23 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -60,6 +60,12 @@ namespace MediaBrowser.Controller.LiveTv /// true if this instance is repeat; otherwise, false. public bool IsRepeat { get; set; } + /// + /// Gets or sets the external series identifier. + /// + /// The external series identifier. + public string ExternalSeriesId { get; set; } + /// /// Gets or sets the episode title. /// diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index 7c590307f..70c6892ef 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -6,6 +6,9 @@ using System.Runtime.Serialization; namespace MediaBrowser.Model.LiveTv { + /// + /// Class SeriesTimerInfoDto. + /// [DebuggerDisplay("Name = {Name}")] public class SeriesTimerInfoDto : BaseTimerInfoDto { @@ -45,6 +48,12 @@ namespace MediaBrowser.Model.LiveTv /// The image tags. public Dictionary ImageTags { get; set; } + /// + /// Gets or sets the external series identifier. + /// + /// The external series identifier. + public string ExternalSeriesId { get; set; } + /// /// Gets a value indicating whether this instance has primary image. /// diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9ff8f7206..177a64ddc 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -220,7 +220,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (enableDelay) { // A hack yes, but need to make sure the file is closed before attempting to delete it - await Task.Delay(3000).ConfigureAwait(false); + await Task.Delay(3000, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 9ffd8a500..2587b1005 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -105,7 +105,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExternalProgramId = info.ProgramId, ServiceName = service.Name, ChannelName = channelName, - ServerId = _appHost.SystemId + ServerId = _appHost.SystemId, + ExternalSeriesId = info.SeriesId }; if (!string.IsNullOrEmpty(info.ChannelId)) @@ -376,7 +377,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv RecordNewOnly = dto.RecordNewOnly, ProgramId = dto.ExternalProgramId, ChannelId = dto.ExternalChannelId, - Id = dto.ExternalId + Id = dto.ExternalId, + SeriesId = dto.ExternalSeriesId }; // Convert internal server id's to external tv provider id's diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 782473bea..9065a8ac2 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -627,6 +627,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; + item.ExternalSeriesId = info.SeriesId; if (isNew) { @@ -1786,7 +1787,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv ImagePath = program.ProviderImagePath, ImageUrl = program.ProviderImageUrl, Name = program.Name, - OfficialRating = program.OfficialRating + OfficialRating = program.OfficialRating, + SeriesId = program.ExternalSeriesId }; } @@ -1829,6 +1831,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Overview = program.Overview; info.ProgramId = programDto.Id; info.ExternalProgramId = program.ExternalId; + info.ExternalSeriesId = program.ExternalSeriesId; if (program.EndDate.HasValue) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b09f8cfef..35f77abcb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -326,6 +326,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { return list; } + channelId = channelId.Substring(ChannelIdPrefix.Length); list.Add(GetMediaSource(info, channelId, "native")); @@ -358,6 +359,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { return null; } + channelId = channelId.Substring(ChannelIdPrefix.Length); return GetMediaSource(info, channelId, streamId); } -- cgit v1.2.3 From 90843b218c9174b8697ddaa296594f9d364fa388 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 16 Aug 2015 18:03:22 -0400 Subject: update recording styles --- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 --- MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs | 6 --- .../LiveTv/EmbyTV/EmbyTV.cs | 54 ++++++++++++++++------ .../LiveTv/LiveTvDtoService.cs | 6 +-- .../LiveTv/LiveTvManager.cs | 5 +- 5 files changed, 42 insertions(+), 35 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 0a1735c23..b54a7aaee 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -60,12 +60,6 @@ namespace MediaBrowser.Controller.LiveTv /// true if this instance is repeat; otherwise, false. public bool IsRepeat { get; set; } - /// - /// Gets or sets the external series identifier. - /// - /// The external series identifier. - public string ExternalSeriesId { get; set; } - /// /// Gets or sets the episode title. /// diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index 70c6892ef..4b88e42f3 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -48,12 +48,6 @@ namespace MediaBrowser.Model.LiveTv /// The image tags. public Dictionary ImageTags { get; set; } - /// - /// Gets or sets the external series identifier. - /// - /// The external series identifier. - public string ExternalSeriesId { get; set; } - /// /// Gets a value indicating whether this instance has primary image. /// diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 177a64ddc..7273ac88e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -251,14 +251,50 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { info.Id = Guid.NewGuid().ToString("N"); - await UpdateTimersForSeriesTimer(info).ConfigureAwait(false); + List epgData; + if (info.RecordAnyChannel) + { + var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); + var channelIds = channels.Select(i => i.Id).ToList(); + epgData = GetEpgDataForChannels(channelIds); + } + else + { + epgData = GetEpgDataForChannel(info.ChannelId); + } + + // populate info.seriesID + var program = epgData.FirstOrDefault(i => string.Equals(i.Id, info.ProgramId, StringComparison.OrdinalIgnoreCase)); + + if (program != null) + { + info.SeriesId = program.SeriesId; + } + else + { + throw new InvalidOperationException("SeriesId for program not found"); + } + _seriesTimerProvider.Add(info); + await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false); } public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) { _seriesTimerProvider.Update(info); - await UpdateTimersForSeriesTimer(info).ConfigureAwait(false); + List epgData; + if (info.RecordAnyChannel) + { + var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); + var channelIds = channels.Select(i => i.Id).ToList(); + epgData = GetEpgDataForChannels(channelIds); + } + else + { + epgData = GetEpgDataForChannel(info.ChannelId); + } + + await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false); } public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken) @@ -597,20 +633,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return _config.GetConfiguration("livetv"); } - private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer) + private async Task UpdateTimersForSeriesTimer(List epgData, SeriesTimerInfo seriesTimer) { - List epgData; - if (seriesTimer.RecordAnyChannel) - { - var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); - var channelIds = channels.Select(i => i.Id).ToList(); - epgData = GetEpgDataForChannels(channelIds); - } - else - { - epgData = GetEpgDataForChannel(seriesTimer.ChannelId); - } - var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList(); var existingTimers = _timerProvider.GetAll() diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 2587b1005..9ffd8a500 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -105,8 +105,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExternalProgramId = info.ProgramId, ServiceName = service.Name, ChannelName = channelName, - ServerId = _appHost.SystemId, - ExternalSeriesId = info.SeriesId + ServerId = _appHost.SystemId }; if (!string.IsNullOrEmpty(info.ChannelId)) @@ -377,8 +376,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv RecordNewOnly = dto.RecordNewOnly, ProgramId = dto.ExternalProgramId, ChannelId = dto.ExternalChannelId, - Id = dto.ExternalId, - SeriesId = dto.ExternalSeriesId + Id = dto.ExternalId }; // Convert internal server id's to external tv provider id's diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 9065a8ac2..782473bea 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -627,7 +627,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; - item.ExternalSeriesId = info.SeriesId; if (isNew) { @@ -1787,8 +1786,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ImagePath = program.ProviderImagePath, ImageUrl = program.ProviderImageUrl, Name = program.Name, - OfficialRating = program.OfficialRating, - SeriesId = program.ExternalSeriesId + OfficialRating = program.OfficialRating }; } @@ -1831,7 +1829,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Overview = program.Overview; info.ProgramId = programDto.Id; info.ExternalProgramId = program.ExternalId; - info.ExternalSeriesId = program.ExternalSeriesId; if (program.EndDate.HasValue) { -- cgit v1.2.3 From ddcebc4ff704d08e5f0a4dab5d14fe40e244b6d1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 20 Aug 2015 22:36:30 -0400 Subject: add tv suggestions --- MediaBrowser.Api/Library/LibraryService.cs | 126 ++++++++++++++++++++- MediaBrowser.Api/Movies/MoviesService.cs | 29 ++++- MediaBrowser.Api/Movies/TrailersService.cs | 39 +------ MediaBrowser.Api/Music/AlbumsService.cs | 50 ++++++++ MediaBrowser.Api/UserLibrary/GenresService.cs | 2 - .../Entities/IHasProgramAttributes.cs | 1 + MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs | 1 - MediaBrowser.Model/ApiClient/IApiClient.cs | 48 +------- MediaBrowser.Model/Dto/BaseItemDto.cs | 9 ++ .../LiveTv/EmbyTV/EmbyTV.cs | 4 +- .../LiveTv/EmbyTV/RecordingHelper.cs | 7 +- 11 files changed, 217 insertions(+), 99 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 50c4ad14f..945e803b2 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -1,4 +1,7 @@ -using MediaBrowser.Controller.Activity; +using MediaBrowser.Api.Movies; +using MediaBrowser.Api.Music; +using MediaBrowser.Controller.Activity; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -9,7 +12,9 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.TV; using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; @@ -238,6 +243,12 @@ namespace MediaBrowser.Api.Library public string Id { get; set; } } + [Route("/Items/{Id}/Similar", "GET", Summary = "Downloads item media")] + [Authenticated(Roles = "download")] + public class GetSimilarItems : BaseGetSimilarItemsFromItem + { + } + /// /// Class LibraryService /// @@ -257,12 +268,14 @@ namespace MediaBrowser.Api.Library private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; private readonly ILiveTvManager _liveTv; + private readonly IChannelManager _channelManager; + private readonly ITVSeriesManager _tvManager; /// /// Initializes a new instance of the class. /// public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, - IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv) + IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager) { _itemRepo = itemRepo; _libraryManager = libraryManager; @@ -273,6 +286,115 @@ namespace MediaBrowser.Api.Library _activityManager = activityManager; _localization = localization; _liveTv = liveTv; + _channelManager = channelManager; + _tvManager = tvManager; + } + + public object Get(GetSimilarItems request) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + if (item is Game) + { + return new GamesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarGames + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + if (item is MusicAlbum) + { + return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarAlbums + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + if (item is MusicArtist) + { + return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarArtists + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + var program = item as IHasProgramAttributes; + var channelItem = item as ChannelVideoItem; + + if (item is Movie || (program != null && program.IsMovie) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Movie && channelItem.ContentType == ChannelMediaContentType.MovieExtra)) + { + return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _channelManager) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarMovies + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + if (item is Series || (program != null && program.IsSeries) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Episode)) + { + return new TvShowsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _tvManager) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarShows + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + return new ItemsResult(); } public object Get(GetMediaFolders request) diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 97e9aa9c8..fe8bae1a5 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -28,6 +28,14 @@ namespace MediaBrowser.Api.Movies { } + /// + /// Class GetSimilarTrailers + /// + [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] + public class GetSimilarTrailers : BaseGetSimilarItemsFromItem + { + } + [Route("/Movies/Recommendations", "GET", Summary = "Gets movie recommendations")] public class GetMovieRecommendations : IReturn, IHasItemFields { @@ -117,6 +125,17 @@ namespace MediaBrowser.Api.Movies return ToOptimizedSerializedResultUsingCache(result); } + public async Task Get(GetSimilarTrailers request) + { + var result = await GetSimilarItemsResult( + // Strip out secondary versions + request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, + + SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + + return ToOptimizedSerializedResultUsingCache(result); + } + public async Task Get(GetMovieRecommendations request) { var user = _userManager.GetUserById(request.UserId); @@ -126,7 +145,7 @@ namespace MediaBrowser.Api.Movies movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies); var listEligibleForCategories = new List(); - var listEligibleForSuggestion = new List (); + var listEligibleForSuggestion = new List(); var list = movies.ToList(); @@ -159,7 +178,7 @@ namespace MediaBrowser.Api.Movies var dtoOptions = GetDtoOptions(request); dtoOptions.Fields = request.GetItemFields().ToList(); - + var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions); return ToOptimizedResult(result); @@ -174,14 +193,14 @@ namespace MediaBrowser.Api.Movies _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); Func filter = i => i.Id != item.Id && includeInSearch(i); - + var inputItems = user == null ? _libraryManager.RootFolder.GetRecursiveChildren(filter) : user.RootFolder.GetRecursiveChildren(user, filter); var list = inputItems.ToList(); - if (item is Movie && user != null && user.Configuration.IncludeTrailersInSuggestions) + if (user != null && user.Configuration.IncludeTrailersInSuggestions) { var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery { @@ -224,7 +243,7 @@ namespace MediaBrowser.Api.Movies } var dtoOptions = GetDtoOptions(request); - + var result = new ItemsResult { Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs index 0847fc7ed..ed197911a 100644 --- a/MediaBrowser.Api/Movies/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -2,15 +2,12 @@ using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -18,14 +15,6 @@ using System.Threading.Tasks; namespace MediaBrowser.Api.Movies { - /// - /// Class GetSimilarTrailers - /// - [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] - public class GetSimilarTrailers : BaseGetSimilarItemsFromItem - { - } - [Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] public class Getrailers : BaseItemsRequest, IReturn { @@ -51,7 +40,6 @@ namespace MediaBrowser.Api.Movies /// private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; private readonly IDtoService _dtoService; private readonly IChannelManager _channelManager; @@ -61,40 +49,15 @@ namespace MediaBrowser.Api.Movies /// The user manager. /// The user data repository. /// The library manager. - public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IChannelManager channelManager) + public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, IChannelManager channelManager) { _userManager = userManager; _userDataRepository = userDataRepository; _libraryManager = libraryManager; - _itemRepo = itemRepo; _dtoService = dtoService; _channelManager = channelManager; } - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - public object Get(GetSimilarTrailers request) - { - var dtoOptions = GetDtoOptions(request); - - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, - _itemRepo, - _libraryManager, - _userDataRepository, - _dtoService, - Logger, - - // Strip out secondary versions - request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, - - SimilarItemsHelper.GetSimiliarityScore); - - return ToOptimizedSerializedResultUsingCache(result); - } - public async Task Get(Getrailers request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs index ea87c3ad3..548598d42 100644 --- a/MediaBrowser.Api/Music/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; @@ -16,6 +17,11 @@ namespace MediaBrowser.Api.Music { } + [Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")] + public class GetSimilarArtists : BaseGetSimilarItemsFromItem + { + } + [Authenticated] public class AlbumsService : BaseApiService { @@ -44,6 +50,17 @@ namespace MediaBrowser.Api.Music _dtoService = dtoService; } + public object Get(GetSimilarArtists request) + { + var result = GetSimilarItemsResult( + + request, + + SimilarItemsHelper.GetSimiliarityScore); + + return ToOptimizedSerializedResultUsingCache(result); + } + /// /// Gets the specified request. /// @@ -65,6 +82,39 @@ namespace MediaBrowser.Api.Music return ToOptimizedSerializedResultUsingCache(result); } + private ItemsResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func, List, BaseItem, int> getSimilarityScore) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + var inputItems = _libraryManager.GetArtists(user.RootFolder.GetRecursiveChildren(user, i => i is IHasArtist).OfType()); + + var list = inputItems.ToList(); + + var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList(); + + IEnumerable returnItems = items; + + if (request.Limit.HasValue) + { + returnItems = returnItems.Take(request.Limit.Value); + } + + var dtoOptions = GetDtoOptions(request); + + var result = new ItemsResult + { + Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), + + TotalRecordCount = items.Count + }; + + return result; + } + /// /// Gets the album similarity score. /// diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 9e56907da..d383bd0ad 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -1,12 +1,10 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs index 391c8f7a7..9938a4489 100644 --- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs +++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs @@ -11,6 +11,7 @@ namespace MediaBrowser.Controller.Entities bool IsKids { get; set; } bool IsRepeat { get; set; } bool? IsHD { get; set; } + bool IsSeries { get; set; } bool IsLive { get; set; } bool IsPremiere { get; set; } ProgramAudio? Audio { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs index 9fc60beb9..ba0b82a0b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs @@ -37,7 +37,6 @@ namespace MediaBrowser.Controller.LiveTv string ExternalId { get; set; } string EpisodeTitle { get; set; } - bool IsSeries { get; set; } string SeriesTimerId { get; set; } RecordingStatus Status { get; set; } DateTime? EndDate { get; set; } diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index e52e7535b..6d441ccf8 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -353,39 +353,7 @@ namespace MediaBrowser.Model.ApiClient /// The query. /// The cancellation token. /// Task{ItemsResult}. - Task GetSimilarMoviesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets the similar trailers async. - /// - /// The query. - /// The cancellation token. - /// Task{ItemsResult}. - Task GetSimilarTrailersAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets the similar series async. - /// - /// The query. - /// The cancellation token. - /// Task{ItemsResult}. - Task GetSimilarSeriesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets the similar albums async. - /// - /// The query. - /// The cancellation token. - /// Task{ItemsResult}. - Task GetSimilarAlbumsAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets the similar games async. - /// - /// The query. - /// The cancellation token. - /// Task{ItemsResult}. - Task GetSimilarGamesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); + Task GetSimilarItemsAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); /// /// Gets the people async. @@ -442,20 +410,6 @@ namespace MediaBrowser.Model.ApiClient /// Task{ItemsResult}. Task GetGenresAsync(ItemsByNameQuery query); - /// - /// Gets the music genres async. - /// - /// The query. - /// Task{ItemsResult}. - Task GetMusicGenresAsync(ItemsByNameQuery query); - - /// - /// Gets the game genres async. - /// - /// The query. - /// Task{ItemsResult}. - Task GetGameGenresAsync(ItemsByNameQuery query); - /// /// Gets the studios async. /// diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index aa68e09a0..ac8fa3370 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1081,6 +1081,15 @@ namespace MediaBrowser.Model.Dto get { return StringHelper.EqualsIgnoreCase(Type, "Studio"); } } + [IgnoreDataMember] + public bool SupportsSimilarItems + { + get + { + return IsType("Movie") || IsType("Series") || IsType("MusicAlbum") || IsType("MusicArtist") || IsType("Program") || IsType("Recording") || IsType("ChannelVideoItem") || IsType("Game"); + } + } + /// /// Occurs when [property changed]. /// diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index ebb5037d0..200c6c9a6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -517,7 +517,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recordPath = Path.Combine(recordPath, "TV", _fileSystem.GetValidFilename(info.Name)); } - recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info))); + var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts"; + + recordPath = Path.Combine(recordPath, recordingFileName); Directory.CreateDirectory(Path.GetDirectoryName(recordPath)); var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index 1b8cd2e61..f8f65c6d5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { if (info == null) { - return timer.ProgramId + ".ts"; + return timer.ProgramId; } var name = info.Name; @@ -52,7 +52,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { name += " " + info.OriginalAirDate.Value.ToString("yyyy-MM-dd"); } - else if (!string.IsNullOrWhiteSpace(info.EpisodeTitle)) + + if (!string.IsNullOrWhiteSpace(info.EpisodeTitle)) { name += " " + info.EpisodeTitle; } @@ -63,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV name += " (" + info.ProductionYear + ")"; } - return name + ".ts"; + return name; } } } -- cgit v1.2.3 From 2dfb9f3c942fbe0e15b46a9b2498b26cc34f682e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 21 Aug 2015 12:54:11 -0400 Subject: update channels --- MediaBrowser.Model/Configuration/ChannelOptions.cs | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Configuration/ChannelOptions.cs b/MediaBrowser.Model/Configuration/ChannelOptions.cs index dfefa4edc..9bd0ef9c5 100644 --- a/MediaBrowser.Model/Configuration/ChannelOptions.cs +++ b/MediaBrowser.Model/Configuration/ChannelOptions.cs @@ -3,19 +3,6 @@ public class ChannelOptions { public int? PreferredStreamingWidth { get; set; } - public string DownloadPath { get; set; } - public int? MaxDownloadAge { get; set; } - - public string[] DownloadingChannels { get; set; } - - public double? DownloadSizeLimit { get; set; } - - public ChannelOptions() - { - DownloadingChannels = new string[] { }; - DownloadSizeLimit = .5; - MaxDownloadAge = 30; - } } } \ No newline at end of file -- cgit v1.2.3 From 5de40ed147ca272450e9b728078cab606741dc52 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 22 Aug 2015 12:30:36 -0400 Subject: display top plugins --- MediaBrowser.Model/Updates/PackageInfo.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs index 5945f87ad..191deeb8f 100644 --- a/MediaBrowser.Model/Updates/PackageInfo.cs +++ b/MediaBrowser.Model/Updates/PackageInfo.cs @@ -159,6 +159,12 @@ namespace MediaBrowser.Model.Updates /// true if [enable in application store]; otherwise, false. public bool enableInAppStore { get; set; } + /// + /// Gets or sets the installs. + /// + /// The installs. + public int installs { get; set; } + /// /// Initializes a new instance of the class. /// -- cgit v1.2.3 From 795a8ab33b6a8937ee7c6c4d3524d4a8b1e2ba33 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 22 Aug 2015 15:46:55 -0400 Subject: added auto-organize setting --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + .../FileOrganization/EpisodeFileOrganizer.cs | 11 ++++- .../FileOrganization/TvFolderOrganizer.cs | 15 +------ .../LiveTv/EmbyTV/EmbyTV.cs | 51 ++++++++++++++++++++-- 4 files changed, 59 insertions(+), 19 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c5e8f4636..7881231a2 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -7,6 +7,7 @@ namespace MediaBrowser.Model.LiveTv public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } public string RecordingPath { get; set; } + public bool EnableAutoOrganize { get; set; } public List TunerHosts { get; set; } public List ListingProviders { get; set; } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index e134670e3..06b72e4ef 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -43,6 +43,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _providerManager = providerManager; } + public Task OrganizeEpisodeFile(string path, CancellationToken cancellationToken) + { + var options = _config.GetAutoOrganizeOptions().TvOptions; + + return OrganizeEpisodeFile(path, options, false, cancellationToken); + } + public async Task OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting, CancellationToken cancellationToken) { _logger.Info("Sorting file {0}", path); @@ -56,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization FileSize = new FileInfo(path).Length }; - var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions(); + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger()); var episodeInfo = resolver.Resolve(path, false) ?? @@ -254,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization .ToList(); var targetFilenameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath); - + foreach (var file in files) { directory = Path.GetDirectoryName(file); diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index 557b531b4..0caa8c26e 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -48,8 +48,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization progress.Report(10); - var scanLibrary = false; - if (eligibleFiles.Count > 0) { var numComplete = 0; @@ -61,12 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization try { - var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); - - if (result.Status == FileSortingStatus.Success) - { - scanLibrary = true; - } + await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -106,12 +99,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } - if (scanLibrary) - { - await _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None) - .ConfigureAwait(false); - } - progress.Report(100); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2f1b9d03e..96e14a21c 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -3,14 +3,20 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.FileOrganization; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; +using MediaBrowser.Model.FileOrganization; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; +using MediaBrowser.Server.Implementations.FileOrganization; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -21,12 +27,12 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { - public class EmbyTV : ILiveTvService/*, IHasRegistrationInfo*/, IDisposable + public class EmbyTV : ILiveTvService, IHasRegistrationInfo, IDisposable { private readonly IApplicationHost _appHpst; private readonly ILogger _logger; private readonly IHttpClient _httpClient; - private readonly IConfigurationManager _config; + private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; private readonly ItemDataProvider _recordingProvider; @@ -37,9 +43,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IFileSystem _fileSystem; private readonly ISecurityManager _security; + private readonly ILibraryMonitor _libraryMonitor; + private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly IFileOrganizationService _organizationService; + public static EmbyTV Current; - public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security) + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService) { Current = this; @@ -49,6 +60,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _config = config; _fileSystem = fileSystem; _security = security; + _libraryManager = libraryManager; + _libraryMonitor = libraryMonitor; + _providerManager = providerManager; + _organizationService = organizationService; _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; @@ -610,6 +625,36 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _recordingProvider.Update(recording); _timerProvider.Delete(timer); _logger.Info("Recording was a success"); + + if (recording.Status == RecordingStatus.Completed) + { + OnSuccessfulRecording(recording); + } + } + + private async void OnSuccessfulRecording(RecordingInfo recording) + { + if (GetConfiguration().EnableAutoOrganize) + { + if (recording.IsSeries) + { + try + { + var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); + + var result = await organize.OrganizeEpisodeFile(recording.Path, CancellationToken.None).ConfigureAwait(false); + + if (result.Status == FileSortingStatus.Success) + { + _recordingProvider.Delete(recording); + } + } + catch (Exception ex) + { + _logger.ErrorException("Error processing new recording", ex); + } + } + } } private ProgramInfo GetProgramInfoFromCache(string channelId, string programId) -- cgit v1.2.3 From 474cbbb87a51cb0fe82c408789c75b3971b58227 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 23 Aug 2015 22:08:20 -0400 Subject: added default padding settings --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 5 ++++- .../Library/LibraryManager.cs | 2 +- .../Library/MediaSourceManager.cs | 5 ++++- MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 6 ++++-- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 3 +-- .../LiveTv/LiveTvMediaSourceProvider.cs | 7 ++++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 13 +++++++++++-- SharedVersion.cs | 4 ++-- 8 files changed, 33 insertions(+), 12 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 7881231a2..2b45422ec 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -11,7 +11,10 @@ namespace MediaBrowser.Model.LiveTv public List TunerHosts { get; set; } public List ListingProviders { get; set; } - + + public int PrePaddingSeconds { get; set; } + public int PostPaddingSeconds { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a67e3d732..cc9d9551c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -937,7 +937,7 @@ namespace MediaBrowser.Server.Implementations.Library (item as MusicArtist).IsAccessedByName = true; } - var task = item.UpdateToRepository(ItemUpdateType.None, CancellationToken.None); + var task = CreateItem(item, CancellationToken.None); Task.WaitAll(task); } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index c5ff100f9..1f4dff277 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -483,7 +483,10 @@ namespace MediaBrowser.Server.Implementations.Library var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase)); - return new Tuple(provider, keys[1]); + var splitIndex = key.IndexOf(LiveStreamIdDelimeter); + var keyId = key.Substring(splitIndex + 1); + + return new Tuple(provider, keyId); } private Timer _closeTimer; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 96e14a21c..b69cdacef 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -339,10 +339,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public Task GetNewTimerDefaultsAsync(CancellationToken cancellationToken, ProgramInfo program = null) { + var config = GetConfiguration(); + var defaults = new SeriesTimerInfo() { - PostPaddingSeconds = 0, - PrePaddingSeconds = 0, + PostPaddingSeconds = Math.Max(config.PostPaddingSeconds, 0), + PrePaddingSeconds = Math.Max(config.PrePaddingSeconds, 0), RecordAnyChannel = false, RecordAnyTime = false, RecordNewOnly = false diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 1721d6101..653adb716 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -889,8 +889,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (query.Limit.HasValue) { - programs = programs.Take(query.Limit.Value) - .OrderBy(i => i.StartDate); + programs = programs.Take(query.Limit.Value); } programList = programs.ToList(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 66a21830e..d9d9b76b9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -125,7 +125,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv const bool isAudio = false; var keys = openToken.Split(new[] { StreamIdDelimeter }, 3); - var mediaSourceId = keys.Length >= 3 ? keys[2] : null; + string mediaSourceId = null; + + if (keys.Length >= 3) + { + mediaSourceId = openToken.Substring(keys[0].Length + keys[1].Length + 2); + } if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 5890e24eb..4bbbf5a4d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -22,7 +22,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly IHttpClient _httpClient; private readonly IJsonSerializer _jsonSerializer; - public HdHomerunHost(IConfigurationManager config, ILogger logger, IHttpClient httpClient, IJsonSerializer jsonSerializer) : base(config, logger) + public HdHomerunHost(IConfigurationManager config, ILogger logger, IHttpClient httpClient, IJsonSerializer jsonSerializer) + : base(config, logger) { _httpClient = httpClient; _jsonSerializer = jsonSerializer; @@ -166,6 +167,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var url = info.Url; + if (string.IsNullOrWhiteSpace(url)) + { + throw new ArgumentException("Invalid tuner info"); + } + if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { url = "http://" + url; @@ -382,7 +388,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun public async Task Validate(TunerHostInfo info) { - await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); + if (info.IsEnabled) + { + await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); + } } protected override async Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) diff --git a/SharedVersion.cs b/SharedVersion.cs index 3d8be801e..2b8644211 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5713.0")] +[assembly: AssemblyVersion("3.0.*")] +//[assembly: AssemblyVersion("3.0.5713.0")] -- cgit v1.2.3 From 92ff7414ae25ccd7c8ce5a09154b190094293162 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 24 Aug 2015 14:22:44 -0400 Subject: update detail page --- MediaBrowser.Model/ApiClient/IApiClient.cs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 6d441ccf8..c2524378e 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -1148,14 +1148,6 @@ namespace MediaBrowser.Model.ApiClient /// Task. Task CancelLiveTvSeriesTimerAsync(string id, CancellationToken cancellationToken = default(CancellationToken)); - /// - /// Deletes the live tv recording asynchronous. - /// - /// The identifier. - /// The cancellation token. - /// Task. - Task DeleteLiveTvRecordingAsync(string id, CancellationToken cancellationToken = default(CancellationToken)); - /// /// Gets the default timer information. /// -- cgit v1.2.3 From 8046a514187f0ef003c2d828dcf31de6e85ecedb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 24 Aug 2015 23:13:04 -0400 Subject: add more live tv buttons --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 11 +++++- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 6 ++++ .../LiveTv/LiveTvManager.cs | 40 +++++++--------------- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 4 +-- .../Persistence/SqliteItemRepository.cs | 34 +++++++++++++++++- 5 files changed, 64 insertions(+), 31 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index d47a7e2d6..07e64c98d 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -78,6 +78,14 @@ namespace MediaBrowser.Api.LiveTv /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Fields { get; set; } + + [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public bool AddCurrentProgram { get; set; } + + public GetChannels() + { + AddCurrentProgram = true; + } } [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")] @@ -582,7 +590,8 @@ namespace MediaBrowser.Api.LiveTv IsFavorite = request.IsFavorite, IsLiked = request.IsLiked, IsDisliked = request.IsDisliked, - EnableFavoriteSorting = request.EnableFavoriteSorting + EnableFavoriteSorting = request.EnableFavoriteSorting, + AddCurrentProgram = request.AddCurrentProgram }, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 900537b7a..3a6ad0444 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -53,5 +53,11 @@ namespace MediaBrowser.Model.LiveTv /// /// The limit. public int? Limit { get; set; } + + /// + /// Gets or sets a value indicating whether [add current program]. + /// + /// true if [add current program]; otherwise, false. + public bool AddCurrentProgram { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 653adb716..9cd4a2334 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -251,13 +251,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv var now = DateTime.UtcNow; - var programs = _libraryManager.QueryItems(new InternalItemsQuery + var programs = query.AddCurrentProgram ? _libraryManager.QueryItems(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, MaxStartDate = now, - MinEndDate = now + MinEndDate = now, + ChannelIds = internalResult.Items.Select(i => i.Id.ToString("N")).ToArray() - }).Items.Cast().OrderBy(i => i.StartDate).ToList(); + }).Items.Cast().OrderBy(i => i.StartDate).ToList() : new List(); foreach (var channel in internalResult.Items) { @@ -776,7 +777,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsMovie = query.IsMovie, IsSports = query.IsSports, IsKids = query.IsKids, - Genres = query.Genres + Genres = query.Genres, + StartIndex = query.StartIndex, + Limit = query.Limit, + SortBy = query.SortBy, + SortOrder = query.SortOrder ?? SortOrder.Ascending }; var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -802,29 +807,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - IEnumerable programs = _libraryManager.QueryItems(internalQuery).Items.Cast(); - - programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending) - .Cast(); - - var programList = programs.ToList(); - IEnumerable returnPrograms = programList; - - if (query.StartIndex.HasValue) - { - returnPrograms = returnPrograms.Skip(query.StartIndex.Value); - } + var queryResult = _libraryManager.QueryItems(internalQuery); - if (query.Limit.HasValue) - { - returnPrograms = returnPrograms.Take(query.Limit.Value); - } - - var returnArray = returnPrograms - .Select(i => - { - return _dtoService.GetBaseItemDto(i, options, user); - }) + var returnArray = queryResult.Items + .Select(i => _dtoService.GetBaseItemDto(i, options, user)) .ToArray(); await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); @@ -832,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var result = new QueryResult { Items = returnArray, - TotalRecordCount = programList.Count + TotalRecordCount = queryResult.TotalRecordCount }; return result; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 4bbbf5a4d..cab21bc3a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { - string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); using (var stream = await _httpClient.Get(new HttpRequestOptions() { @@ -398,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false); - return info.Any(i => i.Status == LiveTvTunerStatus.Available); + return info.Any(i => i.Status == LiveTvTunerStatus.Available || string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase)); } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 3ec45c4de..f6a04f303 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -712,6 +712,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -719,6 +721,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + _logger.Debug(cmd.CommandText); + var list = new List(); var count = 0; @@ -747,6 +751,28 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + private string GetOrderByText(InternalItemsQuery query) + { + if (query.SortBy == null || query.SortBy.Length == 0) + { + return string.Empty; + } + + var sortOrder = query.SortOrder == SortOrder.Descending ? "DESC" : "ASC"; + + return " ORDER BY " + string.Join(",", query.SortBy.Select(i => MapOrderByField(i) + " " + sortOrder).ToArray()); + } + + private string MapOrderByField(string name) + { + if (string.Equals(name, "sortname", StringComparison.OrdinalIgnoreCase)) + { + return "name"; + } + + return name; + } + public List GetItemIdsList(InternalItemsQuery query) { if (query == null) @@ -768,6 +794,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -816,6 +844,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -985,7 +1015,9 @@ namespace MediaBrowser.Server.Implementations.Persistence string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM TypedBaseItems {0} ORDER BY DateCreated DESC LIMIT {1})", + var orderBy = GetOrderByText(query); + + whereClauses.Add(string.Format("guid NOT IN (SELECT guid FROM TypedBaseItems {0}" + orderBy + " LIMIT {1})", pagingWhereText, query.StartIndex.Value.ToString(CultureInfo.InvariantCulture))); } -- cgit v1.2.3 From 5b21ec6747f5c1eef8b44ad8ead4f89ed715a501 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 26 Aug 2015 21:31:54 -0400 Subject: update interval trigger --- MediaBrowser.Api/StartupWizardService.cs | 1 + .../ScheduledTasks/IntervalTrigger.cs | 13 ++- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Dlna/DlnaManager.cs | 3 +- MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 4 +- MediaBrowser.Dlna/Profiles/KodiProfile.cs | 97 ++++++++++++++++++++++ .../Configuration/ServerConfiguration.cs | 6 ++ .../MediaInfo/SubtitleScheduledTask.cs | 2 +- .../IO/LibraryMonitor.cs | 20 +++++ .../LiveTv/Listings/SchedulesDirect.cs | 9 +- .../Persistence/CleanDatabaseScheduledTask.cs | 14 +++- .../Persistence/SqliteItemRepository.cs | 26 +++++- .../ScheduledTasks/RefreshMediaLibraryTask.cs | 22 +++-- 13 files changed, 195 insertions(+), 24 deletions(-) create mode 100644 MediaBrowser.Dlna/Profiles/KodiProfile.cs (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 9eb96873b..e9ac45fa2 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -72,6 +72,7 @@ namespace MediaBrowser.Api _config.Configuration.EnableUserSpecificUserViews = true; _config.Configuration.EnableCustomPathSubFolders = true; _config.Configuration.DisableXmlSavers = true; + _config.Configuration.DisableStartupScan = true; _config.SaveConfiguration(); } diff --git a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs index 15109be4f..b615adf81 100644 --- a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs +++ b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs @@ -30,6 +30,17 @@ namespace MediaBrowser.Common.ScheduledTasks /// public TaskExecutionOptions TaskOptions { get; set; } + /// + /// Gets or sets the first run delay. + /// + /// The first run delay. + public TimeSpan FirstRunDelay { get; set; } + + public IntervalTrigger() + { + FirstRunDelay = TimeSpan.FromHours(1); + } + /// /// Stars waiting for the trigger action /// @@ -41,7 +52,7 @@ namespace MediaBrowser.Common.ScheduledTasks var triggerDate = lastResult != null ? lastResult.EndTimeUtc.Add(Interval) : - DateTime.UtcNow.Add(Interval); + DateTime.UtcNow.Add(FirstRunDelay); if (DateTime.UtcNow > triggerDate) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cd5c39173..a333fc6e9 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Entities public virtual string Path { get; set; } [IgnoreDataMember] - protected internal bool IsOffline { get; set; } + public bool IsOffline { get; set; } /// /// Returns the folder containing the item. diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 9ce62034b..124d0e675 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -547,7 +547,8 @@ namespace MediaBrowser.Dlna new DefaultProfile(), new PopcornHourProfile(), new VlcProfile(), - new BubbleUpnpProfile() + new BubbleUpnpProfile(), + new KodiProfile() }; foreach (var item in list) diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index 2a495638a..055173a7c 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -166,7 +166,9 @@ - + + Designer + diff --git a/MediaBrowser.Dlna/Profiles/KodiProfile.cs b/MediaBrowser.Dlna/Profiles/KodiProfile.cs new file mode 100644 index 000000000..75c323a1a --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/KodiProfile.cs @@ -0,0 +1,97 @@ +using MediaBrowser.Model.Dlna; +using System.Xml.Serialization; + +namespace MediaBrowser.Dlna.Profiles +{ + [XmlRoot("Profile")] + public class KodiProfile : DefaultProfile + { + public KodiProfile() + { + Name = "Kodi"; + + MaxStreamingBitrate = 100000000; + MaxStaticBitrate = 100000000; + MusicStreamingTranscodingBitrate = 1280000; + MusicSyncBitrate = 1280000; + + TimelineOffsetSeconds = 5; + + Identification = new DeviceIdentification + { + ModelName = "Kodi", + + Headers = new[] + { + new HttpHeaderInfo {Name = "User-Agent", Value = "Kodi", Match = HeaderMatchType.Substring} + } + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new TranscodingProfile + { + Container = "ts", + Type = DlnaProfileType.Video, + AudioCodec = "aac", + VideoCodec = "h264" + }, + + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "", + Type = DlnaProfileType.Photo, + } + }; + + ResponseProfiles = new ResponseProfile[] { }; + + ContainerProfiles = new ContainerProfile[] { }; + + CodecProfiles = new CodecProfile[] { }; + + SubtitleProfiles = new[] + { + new SubtitleProfile + { + Format = "srt", + Method = SubtitleDeliveryMethod.External, + }, + + new SubtitleProfile + { + Format = "sub", + Method = SubtitleDeliveryMethod.External, + } + }; + } + } +} diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 46f9db580..07d5905c6 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -98,6 +98,12 @@ namespace MediaBrowser.Model.Configuration /// true if [enable localized guids]; otherwise, false. public bool EnableLocalizedGuids { get; set; } + /// + /// Gets or sets a value indicating whether [disable startup scan]. + /// + /// true if [disable startup scan]; otherwise, false. + public bool DisableStartupScan { get; set; } + /// /// Gets or sets a value indicating whether [enable library metadata sub folder]. /// diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 0f092b554..4953621f5 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -131,7 +131,7 @@ namespace MediaBrowser.Providers.MediaInfo { return new ITaskTrigger[] { - new DailyTrigger { TimeOfDay = TimeSpan.FromHours(3) }, + new IntervalTrigger{ Interval = TimeSpan.FromHours(8)} }; } } diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index e1c529187..5bd26ce18 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.ScheduledTasks; @@ -700,4 +701,23 @@ namespace MediaBrowser.Server.Implementations.IO } } } + + public class LibraryMonitorStartup : IServerEntryPoint + { + private readonly ILibraryMonitor _monitor; + + public LibraryMonitorStartup(ILibraryMonitor monitor) + { + _monitor = monitor; + } + + public void Run() + { + _monitor.Start(); + } + + public void Dispose() + { + } + } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 708891e68..cb5a37401 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -438,8 +438,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return lineups; } - _logger.Info("Headends on account "); - var options = new HttpRequestOptions() { Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location, @@ -454,16 +452,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings using (Stream responce = await _httpClient.Get(options).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream>(responce); - _logger.Info("Lineups on account "); + if (root != null) { foreach (ScheduleDirect.Headends headend in root) { - _logger.Info("Headend: " + headend.headend); foreach (ScheduleDirect.Lineup lineup in headend.lineups) { - _logger.Info("Headend: " + lineup.uri); - lineups.Add(new NameIdPair { Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, @@ -474,7 +469,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } else { - _logger.Info("No lineups on account"); + _logger.Info("No lineups available"); } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs index 69e04c072..7a993b7db 100644 --- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs @@ -1,14 +1,15 @@ using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Logging; namespace MediaBrowser.Server.Implementations.Persistence { @@ -17,12 +18,14 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly ILibraryManager _libraryManager; private readonly IItemRepository _itemRepo; private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; - public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger) + public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config) { _libraryManager = libraryManager; _itemRepo = itemRepo; _logger = logger; + _config = config; } public string Name @@ -53,7 +56,6 @@ namespace MediaBrowser.Server.Implementations.Persistence var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery { IsCurrentSchema = false, - Limit = 100000, // These are constantly getting regenerated so don't bother with them here ExcludeItemTypes = new[] { typeof(LiveTvProgram).Name } @@ -81,6 +83,12 @@ namespace MediaBrowser.Server.Implementations.Persistence progress.Report(percent * 100); } + if (!_config.Configuration.DisableStartupScan) + { + _config.Configuration.DisableStartupScan = true; + _config.SaveConfiguration(); + } + progress.Report(100); } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 71578d1e0..806e86a5a 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deletePeopleCommand; private IDbCommand _savePersonCommand; - private const int LatestSchemaVersion = 4; + private const int LatestSchemaVersion = 6; /// /// Initializes a new instance of the class. @@ -173,6 +173,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "DateCreated", "DATETIME"); _connection.AddColumn(_logger, "TypedBaseItems", "DateModified", "DATETIME"); + _connection.AddColumn(_logger, "TypedBaseItems", "ForcedSortName", "Text"); + _connection.AddColumn(_logger, "TypedBaseItems", "IsOffline", "BIT"); + PrepareStatements(); _mediaStreamsRepository.Initialize(); @@ -223,7 +226,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "VoteCount", "DisplayMediaType", "DateCreated", - "DateModified" + "DateModified", + "ForcedSortName", + "IsOffline" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -391,6 +396,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = item.DateCreated; _saveItemCommand.GetParameter(index++).Value = item.DateModified; + _saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; + _saveItemCommand.GetParameter(index++).Value = item.IsOffline; + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -948,7 +956,6 @@ namespace MediaBrowser.Server.Implementations.Persistence } var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); - if (includeTypes.Length == 1) { whereClauses.Add("type=@type"); @@ -959,6 +966,19 @@ namespace MediaBrowser.Server.Implementations.Persistence var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'").ToArray()); whereClauses.Add(string.Format("type in ({0})", inClause)); } + + var excludeTypes = query.ExcludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); + if (excludeTypes.Length == 1) + { + whereClauses.Add("type<>@type"); + cmd.Parameters.Add(cmd, "@type", DbType.String).Value = excludeTypes[0]; + } + else if (excludeTypes.Length > 1) + { + var inClause = string.Join(",", excludeTypes.Select(i => "'" + i + "'").ToArray()); + whereClauses.Add(string.Format("type not in ({0})", inClause)); + } + if (query.ChannelIds.Length == 1) { whereClauses.Add("ChannelId=@ChannelId"); diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs index ed284a90d..8cb76393e 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.ScheduledTasks; +using System.Linq; +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Server.Implementations.Library; using System; @@ -17,14 +19,16 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// The _library manager /// private readonly ILibraryManager _libraryManager; + private readonly IServerConfigurationManager _config; /// /// Initializes a new instance of the class. /// /// The library manager. - public RefreshMediaLibraryTask(ILibraryManager libraryManager) + public RefreshMediaLibraryTask(ILibraryManager libraryManager, IServerConfigurationManager config) { _libraryManager = libraryManager; + _config = config; } /// @@ -33,12 +37,18 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// IEnumerable{BaseTaskTrigger}. public IEnumerable GetDefaultTriggers() { - return new ITaskTrigger[] { - - new StartupTrigger(), + var list = new ITaskTrigger[] { new IntervalTrigger{ Interval = TimeSpan.FromHours(8)} - }; + + }.ToList(); + + if (!_config.Configuration.DisableStartupScan) + { + list.Add(new StartupTrigger()); + } + + return list; } /// -- cgit v1.2.3 From 4ca526979ddb665ce905cd5943738a2c5657ab31 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 27 Aug 2015 11:58:07 -0400 Subject: 3.0.5713.4 --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 17 +-- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 32 ++++- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 152 +++++++++------------ MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 4 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 26 ++-- MediaBrowser.Model/Entities/MediaStream.cs | 7 +- .../MediaInfo/FFProbeVideoInfo.cs | 16 +-- .../Persistence/SqliteItemRepository.cs | 33 ++++- .../Persistence/SqliteMediaStreamsRepository.cs | 58 +++++++- SharedVersion.cs | 4 +- 10 files changed, 213 insertions(+), 136 deletions(-) (limited to 'MediaBrowser.Model') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 33f3210a9..45e0e8b8a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1634,11 +1634,6 @@ namespace MediaBrowser.Api.Playback private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest) { - if (!EnableStreamCopy) - { - return; - } - if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) { state.OutputVideoCodec = "copy"; @@ -1650,14 +1645,6 @@ namespace MediaBrowser.Api.Playback } } - protected virtual bool EnableStreamCopy - { - get - { - return true; - } - } - private void AttachMediaSourceInfo(StreamState state, MediaSourceInfo mediaSource, VideoStreamRequest videoRequest, @@ -1741,7 +1728,7 @@ namespace MediaBrowser.Api.Playback state.MediaSource = mediaSource; } - private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) + protected virtual bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) { if (videoStream.IsInterlaced) { @@ -1889,7 +1876,7 @@ namespace MediaBrowser.Api.Playback return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase)); } - private bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List supportedAudioCodecs) + protected virtual bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List supportedAudioCodecs) { // Source and target codecs must match if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index b2ffeca3d..1a152790a 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -1,9 +1,11 @@ -using MediaBrowser.Common.IO; +using System.Linq; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; @@ -310,5 +312,33 @@ namespace MediaBrowser.Api.Playback.Hls { return 0; } + + protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) + { + if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0) + { + return false; + } + + var previousSegment = 0; + foreach (var frame in videoStream.KeyFrames) + { + var length = frame - previousSegment; + + // Don't allow really long segments because this could result in long download times + if (length > 10000) + { + return false; + } + previousSegment = frame; + } + + return base.CanStreamCopyVideo(request, videoStream); + } + + protected override bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List supportedAudioCodecs) + { + return false; + } } } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 27429b8db..04979fc3a 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -160,7 +160,6 @@ namespace MediaBrowser.Api.Playback.Hls var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8"); var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex); - var segmentLength = state.SegmentLength; var segmentExtension = GetSegmentFileExtension(state); @@ -169,7 +168,7 @@ namespace MediaBrowser.Api.Playback.Hls if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); } await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); @@ -178,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Hls if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); } else { @@ -214,7 +213,7 @@ namespace MediaBrowser.Api.Playback.Hls DeleteLastFile(playlistPath, segmentExtension, 0); } - request.StartTimeTicks = GetSeekPositionTicks(state, playlistPath, requestedIndex); + request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex); job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false); } @@ -249,37 +248,76 @@ namespace MediaBrowser.Api.Playback.Hls Logger.Info("returning {0}", segmentPath); job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(state, playlistPath, segmentPath, requestedIndex, job, cancellationToken).ConfigureAwait(false); } // 256k private const int BufferSize = 262144; - private long GetSeekPositionTicks(StreamState state, string playlist, int requestedIndex) + private long GetStartPositionTicks(StreamState state, int requestedIndex) { double startSeconds = 0; + var lengths = GetSegmentLengths(state); for (var i = 0; i < requestedIndex; i++) { - var segmentPath = GetSegmentPath(state, playlist, i); + startSeconds += lengths[requestedIndex]; + } + + var position = TimeSpan.FromSeconds(startSeconds).Ticks; + return position; + } - //double length; - //if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length)) - //{ - // Logger.Debug("Found segment length of {0} for index {1}", length, i); - // startSeconds += length; - //} - //else - //{ - // startSeconds += state.SegmentLength; - //} - startSeconds += state.SegmentLength; + private long GetEndPositionTicks(StreamState state, int requestedIndex) + { + double startSeconds = 0; + var lengths = GetSegmentLengths(state); + + for (var i = 0; i <= requestedIndex; i++) + { + startSeconds += lengths[requestedIndex]; } var position = TimeSpan.FromSeconds(startSeconds).Ticks; return position; } + private double[] GetSegmentLengths(StreamState state) + { + var result = new List(); + var encoder = GetVideoEncoder(state); + + if (string.Equals(encoder, "copy", StringComparison.OrdinalIgnoreCase)) + { + var videoStream = state.VideoStream; + if (videoStream.KeyFrames != null && videoStream.KeyFrames.Count > 0) + { + foreach (var frame in videoStream.KeyFrames) + { + var seconds = TimeSpan.FromMilliseconds(frame).TotalSeconds; + seconds -= result.Sum(); + result.Add(seconds); + } + return result.ToArray(); + } + } + + var ticks = state.RunTimeTicks ?? 0; + + var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks; + + while (ticks > 0) + { + var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks; + + result.Add(TimeSpan.FromTicks(length).TotalSeconds); + + ticks -= length; + } + + return result.ToArray(); + } + public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension) { var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType); @@ -384,17 +422,16 @@ namespace MediaBrowser.Api.Playback.Hls return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state)); } - private async Task GetSegmentResult(string playlistPath, + private async Task GetSegmentResult(StreamState state, string playlistPath, string segmentPath, int segmentIndex, - int segmentLength, TranscodingJob transcodingJob, CancellationToken cancellationToken) { // If all transcoding has completed, just return immediately if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath)) { - return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); + return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob); } var segmentFilename = Path.GetFileName(segmentPath); @@ -414,7 +451,7 @@ namespace MediaBrowser.Api.Playback.Hls { if (File.Exists(segmentPath)) { - return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); + return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob); } //break; } @@ -465,13 +502,12 @@ namespace MediaBrowser.Api.Playback.Hls //} cancellationToken.ThrowIfCancellationRequested(); - return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob); + return GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob); } - private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob) + private object GetSegmentResult(StreamState state, string segmentPath, int index, TranscodingJob transcodingJob) { - var segmentEndingSeconds = (1 + index) * segmentLength; - var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks; + var segmentEndingPositionTicks = GetEndPositionTicks(state, index); return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions { @@ -698,26 +734,22 @@ namespace MediaBrowser.Api.Playback.Hls { var state = await GetState(request, CancellationToken.None).ConfigureAwait(false); + var segmentLengths = GetSegmentLengths(state); + var builder = new StringBuilder(); builder.AppendLine("#EXTM3U"); builder.AppendLine("#EXT-X-VERSION:3"); - builder.AppendLine("#EXT-X-TARGETDURATION:" + (state.SegmentLength).ToString(UsCulture)); + builder.AppendLine("#EXT-X-TARGETDURATION:" + Math.Ceiling((segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength)).ToString(UsCulture)); builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0"); var queryStringIndex = Request.RawUrl.IndexOf('?'); var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex); - var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds; - var index = 0; - double segmentLength = state.SegmentLength; - - while (seconds > 0) + foreach (var length in segmentLengths) { - var length = seconds >= state.SegmentLength ? segmentLength : seconds; - builder.AppendLine("#EXTINF:" + length.ToString("0.000000", UsCulture) + ","); builder.AppendLine(string.Format("hlsdynamic/{0}/{1}{2}{3}", @@ -727,7 +759,6 @@ namespace MediaBrowser.Api.Playback.Hls GetSegmentFileExtension(isOutputVideo), queryString)); - seconds -= length; index++; } @@ -850,11 +881,6 @@ namespace MediaBrowser.Api.Playback.Hls args += " -flags +loop-global_header -sc_threshold 0"; } - if (!EnableSplitTranscoding(state)) - { - //args += " -copyts"; - } - return args; } @@ -870,21 +896,6 @@ namespace MediaBrowser.Api.Playback.Hls var toTimeParam = string.Empty; var timestampOffsetParam = string.Empty; - if (EnableSplitTranscoding(state)) - { - var startTime = state.Request.StartTimeTicks ?? 0; - var durationSeconds = ApiEntryPoint.Instance.GetEncodingOptions().ThrottleThresholdInSeconds; - - var endTime = startTime + TimeSpan.FromSeconds(durationSeconds).Ticks; - endTime = Math.Min(endTime, state.RunTimeTicks.Value); - - if (endTime < state.RunTimeTicks.Value) - { - //toTimeParam = " -to " + MediaEncoder.GetTimeParameter(endTime); - toTimeParam = " -t " + MediaEncoder.GetTimeParameter(TimeSpan.FromSeconds(durationSeconds).Ticks); - } - } - if (state.IsOutputVideo && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0) { timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture); @@ -927,36 +938,7 @@ namespace MediaBrowser.Api.Playback.Hls protected override bool EnableThrottling(StreamState state) { - return !EnableSplitTranscoding(state); - } - - private bool EnableSplitTranscoding(StreamState state) - { - return false; - if (string.Equals(Request.QueryString["EnableSplitTranscoding"], "false", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return state.RunTimeTicks.HasValue && state.IsOutputVideo; - } - - protected override bool EnableStreamCopy - { - get - { - return false; - } + return true; } /// diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index a8cd3257c..c49cbc654 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -226,7 +226,9 @@ - + + Designer +