diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 4c6254330e..207486f26a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { if (args.IsDirectory) { - if (args.HasParent()) + if (args.HasParent() || args.HasParent()) { return null; } @@ -80,7 +80,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { return null; } - if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false)) + if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false) || + args.ContainsFileSystemEntryByName("tvshow.nfo")) { return new Series { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 3eb032ba88..b508110cf9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -22,12 +22,15 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Xml; using CommonIO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.FileOrganization; using Microsoft.Win32; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV @@ -867,10 +870,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - private string GetRecordingPath(TimerInfo timer) + private string GetRecordingPath(TimerInfo timer, out string seriesPath) { var recordPath = RecordingPath; var config = GetConfiguration(); + seriesPath = null; if (timer.IsProgramSeries) { @@ -892,6 +896,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV // Can't use the year here in the folder name because it is the year of the episode, not the series. recordPath = Path.Combine(recordPath, folderName); + seriesPath = recordPath; + if (timer.SeasonNumber.HasValue) { folderName = string.Format("Season {0}", timer.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); @@ -980,7 +986,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV RecordingHelper.CopyProgramInfoToTimerInfo(programInfo, timer); } - var recordPath = GetRecordingPath(timer); + string seriesPath = null; + var recordPath = GetRecordingPath(timer, out seriesPath); var recordingStatus = RecordingStatus.New; var isResourceOpen = false; SemaphoreSlim semaphore = null; @@ -1064,7 +1071,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV timer.Status = RecordingStatus.Completed; _timerProvider.Delete(timer); - OnSuccessfulRecording(timer.IsProgramSeries, recordPath); + OnSuccessfulRecording(timer, recordPath, seriesPath); } else if (DateTime.UtcNow < timer.EndDate) { @@ -1132,26 +1139,72 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return new DirectRecorder(_logger, _httpClient, _fileSystem); } - private async void OnSuccessfulRecording(bool isSeries, string path) + private async void OnSuccessfulRecording(TimerInfo timer, string path, string seriesPath) { - if (GetConfiguration().EnableAutoOrganize) + if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize) { - if (isSeries) + try { - try - { - // this is to account for the library monitor holding a lock for additional time after the change is complete. - // ideally this shouldn't be hard-coded - await Task.Delay(30000).ConfigureAwait(false); + // this is to account for the library monitor holding a lock for additional time after the change is complete. + // ideally this shouldn't be hard-coded + await Task.Delay(30000).ConfigureAwait(false); + + var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); - var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); + var result = await organize.OrganizeEpisodeFile(path, _config.GetAutoOrganizeOptions(), false, CancellationToken.None).ConfigureAwait(false); - var result = await organize.OrganizeEpisodeFile(path, _config.GetAutoOrganizeOptions(), false, CancellationToken.None).ConfigureAwait(false); + if (result.Status == FileSortingStatus.Success) + { + return; } - catch (Exception ex) + } + catch (Exception ex) + { + _logger.ErrorException("Error processing new recording", ex); + } + } + + SaveNfo(timer, path, seriesPath); + } + + private void SaveNfo(TimerInfo timer, string recordingPath, string seriesPath) + { + if (timer.IsProgramSeries) + { + SaveSeriesNfo(timer, recordingPath, seriesPath); + } + } + + private void SaveSeriesNfo(TimerInfo timer, string recordingPath, string seriesPath) + { + var nfoPath = Path.Combine(seriesPath, "tvshow.nfo"); + + if (File.Exists(nfoPath)) + { + return; + } + + using (var stream = _fileSystem.GetFileStream(nfoPath, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + var settings = new XmlWriterSettings + { + Indent = true, + Encoding = Encoding.UTF8, + CloseOutput = false + }; + + using (XmlWriter writer = XmlWriter.Create(stream, settings)) + { + writer.WriteStartDocument(true); + writer.WriteStartElement("tvshow"); + + if (!string.IsNullOrWhiteSpace(timer.Name)) { - _logger.ErrorException("Error processing new recording", ex); + writer.WriteElementString("title", timer.Name); } + + writer.WriteEndElement(); + writer.WriteEndDocument(); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index d863c45875..c302633889 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -171,22 +171,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var data = images[imageIndex].data ?? new List(); data = data.OrderByDescending(GetSizeOrder).ToList(); - programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true); + programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 1280); //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false); //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? // GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? // GetProgramImage(ApiUrl, data, "Banner-LO", false) ?? // GetProgramImage(ApiUrl, data, "Banner-LOT", false); - - if (!string.IsNullOrWhiteSpace(programEntry.thumbImage)) - { - var b = true; - } - - if (!string.IsNullOrWhiteSpace(programEntry.bannerImage)) - { - var b = true; - } } } @@ -201,10 +191,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private int GetSizeOrder(ScheduleDirect.ImageData image) { - if (!string.IsNullOrWhiteSpace(image.size)) + if (!string.IsNullOrWhiteSpace(image.height)) { int value; - if (int.TryParse(image.size, out value)) + if (int.TryParse(image.height, out value)) { return value; } @@ -517,20 +507,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return date; } - private string GetProgramImage(string apiUrl, List images, string category, bool returnDefaultImage) + private string GetProgramImage(string apiUrl, List images, string category, bool returnDefaultImage, int desiredWidth) { string url = null; - var logoIndex = images.FindIndex(i => string.Equals(i.category, category, StringComparison.OrdinalIgnoreCase)); - if (logoIndex == -1) + var matches = images + .Where(i => string.Equals(i.category, category, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (matches.Count == 0) { if (!returnDefaultImage) { return null; } - logoIndex = 0; + matches = images; } - var uri = images[logoIndex].uri; + + var match = matches.FirstOrDefault(i => + { + if (!string.IsNullOrWhiteSpace(i.width)) + { + int value; + if (int.TryParse(i.width, out value)) + { + return value <= desiredWidth; + } + } + + return false; + }) ?? matches.FirstOrDefault(); + + if (match == null) + { + return null; + } + + var uri = match.uri; if (!string.IsNullOrWhiteSpace(uri)) {