From d8cf48ae41409ccde5578960186e2d5cc46f9dcd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 31 Mar 2016 15:41:52 -0400 Subject: update satip page --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 71f87ac3a3..660f30cc9c 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -37,6 +37,10 @@ namespace MediaBrowser.Model.LiveTv public string FriendlyName { get; set; } public int Tuners { get; set; } public string DiseqC { get; set; } + public string SourceA { get; set; } + public string SourceB { get; set; } + public string SourceC { get; set; } + public string SourceD { get; set; } public int DataVersion { get; set; } -- cgit v1.2.3 From c9092de032b4166f5907283f35d361ee7c49a3ee Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Sun, 3 Apr 2016 23:46:45 -0700 Subject: allow disabling of hardware transcoding on HDTC-2US --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 4 +++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 660f30cc9c..46f630fe04 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -31,6 +31,7 @@ namespace MediaBrowser.Model.LiveTv public string Type { get; set; } public string DeviceId { get; set; } public bool ImportFavoritesOnly { get; set; } + public bool AllowHWTranscoding { get; set; } public bool IsEnabled { get; set; } public string M3UUrl { get; set; } public string InfoUrl { get; set; } @@ -47,6 +48,7 @@ namespace MediaBrowser.Model.LiveTv public TunerHostInfo() { IsEnabled = true; + AllowHWTranscoding = true; } } @@ -70,4 +72,4 @@ namespace MediaBrowser.Model.LiveTv EnableAllTuners = true; } } -} \ No newline at end of file +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index ef8efbe987..64780a8e31 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -397,7 +397,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); model = model ?? string.Empty; - if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) + if (info.AllowHWTranscoding && (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) { list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false)); -- cgit v1.2.3 From 747518decc3e59a9c6b01f31e5360ce194919d8d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 27 Apr 2016 17:26:28 -0400 Subject: added option to preserve original audio when recording --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 6 ++++-- .../LiveTv/EmbyTV/EncodedRecorder.cs | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 46f630fe04..fc2b155ecd 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -9,6 +9,7 @@ namespace MediaBrowser.Model.LiveTv public string RecordingPath { get; set; } public bool EnableAutoOrganize { get; set; } public bool EnableRecordingEncoding { get; set; } + public bool EnableOriginalAudioWithEncodedRecordings { get; set; } public List TunerHosts { get; set; } public List ListingProviders { get; set; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index d85e8ba3f9..351bc05af6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -927,13 +927,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private async Task GetRecorder() { - if (GetConfiguration().EnableRecordingEncoding) + var config = GetConfiguration(); + + if (config.EnableRecordingEncoding) { var regInfo = await _security.GetRegistrationStatus("embytvrecordingconversion").ConfigureAwait(false); if (regInfo.IsValid) { - return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer); + return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 442f151dd0..63d0846fc1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -12,6 +12,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -23,6 +24,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IApplicationPaths _appPaths; + private readonly LiveTvOptions _liveTvOptions; private bool _hasExited; private Stream _logFileStream; private string _targetPath; @@ -30,13 +32,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IJsonSerializer _json; private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); - public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json) + public EncodedRecorder(ILogger logger, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IApplicationPaths appPaths, IJsonSerializer json, LiveTvOptions liveTvOptions) { _logger = logger; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _appPaths = appPaths; _json = json; + _liveTvOptions = liveTvOptions; } public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) @@ -129,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var copyAudio = new[] { "aac", "mp3" }; var mediaStreams = mediaSource.MediaStreams ?? new List(); - if (mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase))) + if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase))) { return "-codec:a:0 copy"; } -- cgit v1.2.3 From 33c002684e30f910312eef7f796e2efc0607d4a5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 4 May 2016 16:50:47 -0400 Subject: update recording saving --- MediaBrowser.Api/Library/LibraryHelpers.cs | 54 --- .../Library/LibraryStructureService.cs | 43 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 - MediaBrowser.Controller/Library/ILibraryManager.cs | 2 + MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 4 + .../Library/LibraryManager.cs | 68 +++ .../LiveTv/EmbyTV/EmbyTV.cs | 512 +++++++++++++-------- 7 files changed, 403 insertions(+), 281 deletions(-) delete mode 100644 MediaBrowser.Api/Library/LibraryHelpers.cs (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs deleted file mode 100644 index 22a88e2bf1..0000000000 --- a/MediaBrowser.Api/Library/LibraryHelpers.cs +++ /dev/null @@ -1,54 +0,0 @@ -using MediaBrowser.Controller; -using System; -using System.IO; -using System.Linq; -using CommonIO; - -namespace MediaBrowser.Api.Library -{ - /// - /// Class LibraryHelpers - /// - public static class LibraryHelpers - { - /// - /// The shortcut file extension - /// - private const string ShortcutFileExtension = ".mblink"; - /// - /// The shortcut file search - /// - private const string ShortcutFileSearch = "*" + ShortcutFileExtension; - - /// - /// Deletes a shortcut from within a virtual folder, within either the default view or a user view - /// - /// The file system. - /// Name of the virtual folder. - /// The media path. - /// The app paths. - /// The media folder does not exist - public static void RemoveMediaPath(IFileSystem fileSystem, string virtualFolderName, string mediaPath, IServerApplicationPaths appPaths) - { - if (string.IsNullOrWhiteSpace(mediaPath)) - { - throw new ArgumentNullException("mediaPath"); - } - - var rootFolderPath = appPaths.DefaultUserViewsPath; - var path = Path.Combine(rootFolderPath, virtualFolderName); - - if (!fileSystem.DirectoryExists(path)) - { - throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); - } - - var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase)); - - if (!string.IsNullOrEmpty(shortcut)) - { - fileSystem.DeleteFile(shortcut); - } - } - } -} diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 817fd9ce00..3cf0d5d937 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -268,46 +268,7 @@ namespace MediaBrowser.Api.Library /// The request. public void Delete(RemoveVirtualFolder request) { - if (string.IsNullOrWhiteSpace(request.Name)) - { - throw new ArgumentNullException("request"); - } - - var rootFolderPath = _appPaths.DefaultUserViewsPath; - - var path = Path.Combine(rootFolderPath, request.Name); - - if (!_fileSystem.DirectoryExists(path)) - { - throw new DirectoryNotFoundException("The media folder does not exist"); - } - - _libraryMonitor.Stop(); - - try - { - _fileSystem.DeleteDirectory(path, true); - } - finally - { - Task.Run(() => - { - // No need to start if scanning the library because it will handle it - if (request.RefreshLibrary) - { - _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); - } - else - { - // Need to add a delay here or directory watchers may still pick up the changes - var task = Task.Delay(1000); - // Have to block here to allow exceptions to bubble - Task.WaitAll(task); - - _libraryMonitor.Start(); - } - }); - } + _libraryManager.RemoveVirtualFolder(request.Name, request.RefreshLibrary); } /// @@ -364,7 +325,7 @@ namespace MediaBrowser.Api.Library try { - LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, _appPaths); + _libraryManager.RemoveMediaPath(request.Name, request.Path); } finally { diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index db8961a66c..77949d1793 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -129,7 +129,6 @@ - diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 07ba41b3d7..936b97c6e2 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -571,6 +571,8 @@ namespace MediaBrowser.Controller.Library bool IgnoreFile(FileSystemMetadata file, BaseItem parent); void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, bool refreshLibrary); + void RemoveVirtualFolder(string name, bool refreshLibrary); void AddMediaPath(string virtualFolderName, string path); + void RemoveMediaPath(string virtualFolderName, string path); } } \ No newline at end of file diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index fc2b155ecd..4211fbd59f 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -7,8 +7,11 @@ namespace MediaBrowser.Model.LiveTv public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } public string RecordingPath { get; set; } + public string MovieRecordingPath { get; set; } + public string SeriesRecordingPath { get; set; } public bool EnableAutoOrganize { get; set; } public bool EnableRecordingEncoding { get; set; } + public bool EnableRecordingSubfolders { get; set; } public bool EnableOriginalAudioWithEncodedRecordings { get; set; } public List TunerHosts { get; set; } @@ -20,6 +23,7 @@ namespace MediaBrowser.Model.LiveTv public LiveTvOptions() { EnableMovieProviders = true; + EnableRecordingSubfolders = true; TunerHosts = new List(); ListingProviders = new List(); } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 72132c4be1..95d47b380c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -2640,7 +2640,52 @@ namespace MediaBrowser.Server.Implementations.Library } } + public void RemoveVirtualFolder(string name, bool refreshLibrary) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + + var path = Path.Combine(rootFolderPath, name); + + if (!_fileSystem.DirectoryExists(path)) + { + throw new DirectoryNotFoundException("The media folder does not exist"); + } + + _libraryMonitorFactory().Stop(); + + try + { + _fileSystem.DeleteDirectory(path, true); + } + finally + { + Task.Run(() => + { + // No need to start if scanning the library because it will handle it + if (refreshLibrary) + { + ValidateMediaLibrary(new Progress(), CancellationToken.None); + } + else + { + // Need to add a delay here or directory watchers may still pick up the changes + var task = Task.Delay(1000); + // Have to block here to allow exceptions to bubble + Task.WaitAll(task); + + _libraryMonitorFactory().Start(); + } + }); + } + } + private const string ShortcutFileExtension = ".mblink"; + private const string ShortcutFileSearch = "*" + ShortcutFileExtension; public void AddMediaPath(string virtualFolderName, string path) { if (string.IsNullOrWhiteSpace(path)) @@ -2668,5 +2713,28 @@ namespace MediaBrowser.Server.Implementations.Library _fileSystem.CreateShortcut(lnk, path); } + + public void RemoveMediaPath(string virtualFolderName, string mediaPath) + { + if (string.IsNullOrWhiteSpace(mediaPath)) + { + throw new ArgumentNullException("mediaPath"); + } + + var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + var path = Path.Combine(rootFolderPath, virtualFolderName); + + if (!_fileSystem.DirectoryExists(path)) + { + throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); + } + + var shortcut = Directory.EnumerateFiles(path, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrEmpty(shortcut)) + { + _fileSystem.DeleteFile(shortcut); + } + } } } \ 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 df15c38fdd..c5920d3d6a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -26,7 +26,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Power; using Microsoft.Win32; @@ -40,7 +43,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; - private readonly ItemDataProvider _recordingProvider; private readonly ItemDataProvider _seriesTimerProvider; private readonly TimerManager _timerProvider; @@ -56,6 +58,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public static EmbyTV Current; + public event EventHandler DataSourceChanged; + public event EventHandler RecordingStatusChanged; + + private readonly ConcurrentDictionary _activeRecordings = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement) { Current = this; @@ -74,10 +82,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; - _recordingProvider = new ItemDataProvider(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); _seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), powerManagement, _logger); _timerProvider.TimerFired += _timerProvider_TimerFired; + + _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated; + } + + private void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) + { + if (string.Equals(e.Key, "livetv", StringComparison.OrdinalIgnoreCase)) + { + OnRecordingFoldersChanged(); + } } public void Start() @@ -85,6 +102,95 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _timerProvider.RestartTimers(); SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + + CreateRecordingFolders(); + } + + private void OnRecordingFoldersChanged() + { + CreateRecordingFolders(); + } + + private void CreateRecordingFolders() + { + var recordingFolders = GetRecordingFolders(); + + var defaultRecordingPath = DefaultRecordingPath; + if (!recordingFolders.Any(i => i.Locations.Contains(defaultRecordingPath, StringComparer.OrdinalIgnoreCase))) + { + RemovePathFromLibrary(defaultRecordingPath); + } + + var virtualFolders = _libraryManager.GetVirtualFolders() + .ToList(); + + var allExistingPaths = virtualFolders.SelectMany(i => i.Locations).ToList(); + + foreach (var recordingFolder in recordingFolders) + { + var pathsToCreate = recordingFolder.Locations + .Where(i => !allExistingPaths.Contains(i, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + if (pathsToCreate.Count == 0) + { + continue; + } + + try + { + _libraryManager.AddVirtualFolder(recordingFolder.Name, recordingFolder.CollectionType, pathsToCreate.ToArray(), true); + } + catch (Exception ex) + { + _logger.ErrorException("Error creating virtual folder", ex); + } + } + } + + private void RemovePathFromLibrary(string path) + { + var requiresRefresh = false; + var virtualFolders = _libraryManager.GetVirtualFolders() + .ToList(); + + foreach (var virtualFolder in virtualFolders) + { + if (!virtualFolder.Locations.Contains(path, StringComparer.OrdinalIgnoreCase)) + { + continue; + } + + if (virtualFolder.Locations.Count == 1) + { + // remove entire virtual folder + try + { + _libraryManager.RemoveVirtualFolder(virtualFolder.Name, true); + } + catch (Exception ex) + { + _logger.ErrorException("Error removing virtual folder", ex); + } + } + else + { + try + { + _libraryManager.RemoveMediaPath(virtualFolder.Name, path); + requiresRefresh = true; + } + catch (Exception ex) + { + _logger.ErrorException("Error removing media path", ex); + } + } + } + + if (requiresRefresh) + { + _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None); + } } void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) @@ -97,13 +203,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - public event EventHandler DataSourceChanged; - - public event EventHandler RecordingStatusChanged; - - private readonly ConcurrentDictionary _activeRecordings = - new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - public string Name { get { return "Emby"; } @@ -114,6 +213,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV get { return Path.Combine(_config.CommonApplicationPaths.DataPath, "livetv"); } } + private string DefaultRecordingPath + { + get + { + return Path.Combine(DataPath, "recordings"); + } + } + + private string RecordingPath + { + get + { + var path = GetConfiguration().RecordingPath; + + return string.IsNullOrWhiteSpace(path) + ? DefaultRecordingPath + : path; + } + } + public string HomePageUrl { get { return "http://emby.media"; } @@ -280,49 +399,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult(true); } - public async Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) + public Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) { - var remove = _recordingProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, recordingId, StringComparison.OrdinalIgnoreCase)); - if (remove != null) - { - if (!string.IsNullOrWhiteSpace(remove.TimerId)) - { - var enableDelay = _activeRecordings.ContainsKey(remove.TimerId); - - CancelTimerInternal(remove.TimerId); - - if (enableDelay) - { - // A hack yes, but need to make sure the file is closed before attempting to delete it - await Task.Delay(3000, cancellationToken).ConfigureAwait(false); - } - } - - if (!string.IsNullOrWhiteSpace(remove.Path)) - { - try - { - _fileSystem.DeleteFile(remove.Path); - } - catch (DirectoryNotFoundException) - { - - } - catch (FileNotFoundException) - { - - } - catch (Exception ex) - { - _logger.ErrorException("Error deleting recording file {0}", ex, remove.Path); - } - } - _recordingProvider.Delete(remove); - } - else - { - throw new ResourceNotFoundException("Recording not found: " + recordingId); - } + return Task.FromResult(true); } public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken) @@ -424,29 +503,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task> GetRecordingsAsync(CancellationToken cancellationToken) { - var recordings = _recordingProvider.GetAll().ToList(); - var updated = false; - - foreach (var recording in recordings) - { - if (recording.Status == RecordingStatus.InProgress) - { - if (string.IsNullOrWhiteSpace(recording.TimerId) || !_activeRecordings.ContainsKey(recording.TimerId)) - { - recording.Status = RecordingStatus.Cancelled; - recording.DateLastUpdated = DateTime.UtcNow; - _recordingProvider.Update(recording); - updated = true; - } - } - } - - if (updated) - { - recordings = _recordingProvider.GetAll().ToList(); - } - - return recordings; + return new List(); } public Task> GetTimersAsync(CancellationToken cancellationToken) @@ -695,104 +752,124 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken) + private string GetRecordingPath(TimerInfo timer, ProgramInfo info) { - if (timer == null) - { - throw new ArgumentNullException("timer"); - } - - ProgramInfo info = null; - - if (string.IsNullOrWhiteSpace(timer.ProgramId)) - { - _logger.Info("Timer {0} has null programId", timer.Id); - } - else - { - info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); - } - - if (info == null) - { - _logger.Info("Unable to find program with Id {0}. Will search using start date", timer.ProgramId); - info = GetProgramInfoFromCache(timer.ChannelId, timer.StartDate); - } - - if (info == null) - { - throw new InvalidOperationException(string.Format("Program with Id {0} not found", timer.ProgramId)); - } - var recordPath = RecordingPath; + var config = GetConfiguration(); if (info.IsMovie) { - recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name).Trim()); + var customRecordingPath = config.MovieRecordingPath; + if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + { + recordPath = Path.Combine(recordPath, "Movies"); + } + + var folderName = _fileSystem.GetValidFilename(info.Name).Trim(); + if (info.ProductionYear.HasValue) + { + folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")"; + } + recordPath = Path.Combine(recordPath, folderName); } else if (info.IsSeries) { - recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name).Trim()); + var customRecordingPath = config.SeriesRecordingPath; + if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + { + recordPath = Path.Combine(recordPath, "Series"); + } + + var folderName = _fileSystem.GetValidFilename(info.Name).Trim(); + var folderNameWithYear = folderName; + if (info.ProductionYear.HasValue) + { + folderNameWithYear += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")"; + } + + if (Directory.Exists(Path.Combine(recordPath, folderName))) + { + recordPath = Path.Combine(recordPath, folderName); + } + else + { + recordPath = Path.Combine(recordPath, folderNameWithYear); + } if (info.SeasonNumber.HasValue) { - var folderName = string.Format("Season {0}", info.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); + folderName = string.Format("Season {0}", info.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture)); recordPath = Path.Combine(recordPath, folderName); } } else if (info.IsKids) { - recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name).Trim()); + if (config.EnableRecordingSubfolders) + { + recordPath = Path.Combine(recordPath, "Kids"); + } + + var folderName = _fileSystem.GetValidFilename(info.Name).Trim(); + if (info.ProductionYear.HasValue) + { + folderName += " (" + info.ProductionYear.Value.ToString(CultureInfo.InvariantCulture) + ")"; + } + recordPath = Path.Combine(recordPath, folderName); } else if (info.IsSports) { - recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name).Trim()); + if (config.EnableRecordingSubfolders) + { + recordPath = Path.Combine(recordPath, "Sports"); + } + recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim()); } else { - recordPath = Path.Combine(recordPath, "Other", _fileSystem.GetValidFilename(info.Name).Trim()); + if (config.EnableRecordingSubfolders) + { + recordPath = Path.Combine(recordPath, "Other"); + } + recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(info.Name).Trim()); } var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)).Trim() + ".ts"; - recordPath = Path.Combine(recordPath, recordingFileName); + return Path.Combine(recordPath, recordingFileName); + } - var recordingId = info.Id.GetMD5().ToString("N"); - var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, recordingId, StringComparison.OrdinalIgnoreCase)); + private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken) + { + if (timer == null) + { + throw new ArgumentNullException("timer"); + } - if (recording == null) + ProgramInfo info = null; + + if (string.IsNullOrWhiteSpace(timer.ProgramId)) { - recording = new RecordingInfo - { - ChannelId = info.ChannelId, - Id = recordingId, - StartDate = info.StartDate, - EndDate = info.EndDate, - Genres = info.Genres, - 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, - ImagePath = info.ImagePath, - ImageUrl = info.ImageUrl, - OriginalAirDate = info.OriginalAirDate, - Status = RecordingStatus.Scheduled, - Overview = info.Overview, - SeriesTimerId = timer.SeriesTimerId, - TimerId = timer.Id, - ShowId = info.ShowId - }; - _recordingProvider.AddOrUpdate(recording); + _logger.Info("Timer {0} has null programId", timer.Id); + } + else + { + info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); + } + + if (info == null) + { + _logger.Info("Unable to find program with Id {0}. Will search using start date", timer.ProgramId); + info = GetProgramInfoFromCache(timer.ChannelId, timer.StartDate); } + if (info == null) + { + throw new InvalidOperationException(string.Format("Program with Id {0} not found", timer.ProgramId)); + } + + var recordPath = GetRecordingPath(timer, info); + var recordingStatus = RecordingStatus.New; + try { var result = await GetChannelStreamInternal(timer.ChannelId, null, CancellationToken.None).ConfigureAwait(false); @@ -817,11 +894,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _libraryMonitor.ReportFileSystemChangeBeginning(recordPath); - recording.Path = recordPath; - recording.Status = RecordingStatus.InProgress; - recording.DateLastUpdated = DateTime.UtcNow; - _recordingProvider.AddOrUpdate(recording); - var duration = recordingEndDate - DateTime.UtcNow; _logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture)); @@ -846,7 +918,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false); - recording.Status = RecordingStatus.Completed; + recordingStatus = RecordingStatus.Completed; _logger.Info("Recording completed: {0}", recordPath); } finally @@ -862,12 +934,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV catch (OperationCanceledException) { _logger.Info("Recording stopped: {0}", recordPath); - recording.Status = RecordingStatus.Completed; + recordingStatus = RecordingStatus.Completed; } catch (Exception ex) { _logger.ErrorException("Error recording to {0}", ex, recordPath); - recording.Status = RecordingStatus.Error; + recordingStatus = RecordingStatus.Error; } finally { @@ -875,12 +947,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _activeRecordings.TryRemove(timer.Id, out removed); } - recording.DateLastUpdated = DateTime.UtcNow; - _recordingProvider.AddOrUpdate(recording); - - if (recording.Status == RecordingStatus.Completed) + if (recordingStatus == RecordingStatus.Completed) { - OnSuccessfulRecording(recording); + OnSuccessfulRecording(info.IsSeries, recordPath); _timerProvider.Delete(timer); } else if (DateTime.UtcNow < timer.EndDate) @@ -893,7 +962,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV else { _timerProvider.Delete(timer); - _recordingProvider.Delete(recording); } } @@ -948,11 +1016,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return new DirectRecorder(_logger, _httpClient, _fileSystem); } - private async void OnSuccessfulRecording(RecordingInfo recording) + private async void OnSuccessfulRecording(bool isSeries, string path) { if (GetConfiguration().EnableAutoOrganize) { - if (recording.IsSeries) + if (isSeries) { try { @@ -962,12 +1030,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV 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); - } + var result = await organize.OrganizeEpisodeFile(path, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -991,18 +1054,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return epgData.FirstOrDefault(p => Math.Abs(startDateTicks - p.StartDate.Ticks) <= TimeSpan.FromMinutes(3).Ticks); } - private string RecordingPath - { - get - { - var path = GetConfiguration().RecordingPath; - - return string.IsNullOrWhiteSpace(path) - ? Path.Combine(DataPath, "recordings") - : path; - } - } - private LiveTvOptions GetConfiguration() { return _config.GetConfiguration("livetv"); @@ -1010,7 +1061,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private async Task UpdateTimersForSeriesTimer(List epgData, SeriesTimerInfo seriesTimer, bool deleteInvalidTimers) { - var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList(); + var newTimers = GetTimersForSeries(seriesTimer, epgData, true).ToList(); var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false); @@ -1024,7 +1075,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (deleteInvalidTimers) { - var allTimers = GetTimersForSeries(seriesTimer, epgData, new List()) + var allTimers = GetTimersForSeries(seriesTimer, epgData, false) .Select(i => i.Id) .ToList(); @@ -1040,7 +1091,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } - private IEnumerable GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable allPrograms, IReadOnlyList currentRecordings) + private IEnumerable GetTimersForSeries(SeriesTimerInfo seriesTimer, + IEnumerable allPrograms, + bool filterByCurrentRecordings) { if (seriesTimer == null) { @@ -1050,23 +1103,71 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { throw new ArgumentNullException("allPrograms"); } - if (currentRecordings == null) - { - throw new ArgumentNullException("currentRecordings"); - } // Exclude programs that have already ended allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow && i.StartDate > DateTime.UtcNow); allPrograms = GetProgramsForSeries(seriesTimer, allPrograms); - var recordingShowIds = currentRecordings.Select(i => i.ProgramId).Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); - - allPrograms = allPrograms.Where(i => !recordingShowIds.Contains(i.Id, StringComparer.OrdinalIgnoreCase)); + if (filterByCurrentRecordings) + { + allPrograms = allPrograms.Where(i => !IsProgramAlreadyInLibrary(i)); + } return allPrograms.Select(i => RecordingHelper.CreateTimer(i, seriesTimer)); } + private bool IsProgramAlreadyInLibrary(ProgramInfo program) + { + if ((program.EpisodeNumber.HasValue && program.SeasonNumber.HasValue) || !string.IsNullOrWhiteSpace(program.EpisodeTitle)) + { + var seriesIds = _libraryManager.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Name = program.Name + + }).Select(i => i.ToString("N")).ToArray(); + + if (seriesIds.Length == 0) + { + return false; + } + + if (program.EpisodeNumber.HasValue && program.SeasonNumber.HasValue) + { + var result = _libraryManager.GetItemsResult(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Episode).Name }, + ParentIndexNumber = program.SeasonNumber.Value, + IndexNumber = program.EpisodeNumber.Value, + AncestorIds = seriesIds + }); + + if (result.TotalRecordCount > 0) + { + return true; + } + } + + if (!string.IsNullOrWhiteSpace(program.EpisodeTitle)) + { + var result = _libraryManager.GetItemsResult(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Episode).Name }, + Name = program.EpisodeTitle, + AncestorIds = seriesIds + }); + + if (result.TotalRecordCount > 0) + { + return true; + } + } + } + + return false; + } + private IEnumerable GetProgramsForSeries(SeriesTimerInfo seriesTimer, IEnumerable allPrograms) { if (!seriesTimer.RecordAnyTime) @@ -1151,6 +1252,47 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV }); } + public List GetRecordingFolders() + { + var list = new List(); + + var defaultFolder = RecordingPath; + var defaultName = "Recordings"; + + if (Directory.Exists(defaultFolder)) + { + list.Add(new VirtualFolderInfo + { + Locations = new List { defaultFolder }, + Name = defaultName + }); + } + + var customPath = GetConfiguration().MovieRecordingPath; + if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath)) + { + list.Add(new VirtualFolderInfo + { + Locations = new List { customPath }, + Name = "Recorded Movies", + CollectionType = CollectionType.Movies + }); + } + + customPath = GetConfiguration().SeriesRecordingPath; + if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath)) + { + list.Add(new VirtualFolderInfo + { + Locations = new List { customPath }, + Name = "Recorded Series", + CollectionType = CollectionType.TvShows + }); + } + + return list; + } + class ActiveRecordingInfo { public string Path { get; set; } -- cgit v1.2.3 From 99084edabeb1787f28496dffa55fbb260e34ae81 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 May 2016 23:13:38 -0400 Subject: update windows ffmpeg --- MediaBrowser.Api/ApiEntryPoint.cs | 8 ++- MediaBrowser.Api/LiveTv/LiveTvService.cs | 20 ++++++- MediaBrowser.Api/Movies/MoviesService.cs | 1 - MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 5 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 3 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 6 --- .../Entities/Audio/MusicAlbum.cs | 9 ++++ .../Entities/Audio/MusicArtist.cs | 9 ++++ MediaBrowser.Controller/Entities/BaseItem.cs | 11 ++++ MediaBrowser.Controller/Entities/Folder.cs | 49 +++++++++++------ MediaBrowser.Controller/Entities/IHasMetadata.cs | 2 + .../Entities/InternalItemsQuery.cs | 2 + MediaBrowser.Controller/Entities/MusicVideo.cs | 6 --- MediaBrowser.Controller/Entities/TV/Season.cs | 9 ++++ MediaBrowser.Controller/Entities/TV/Series.cs | 9 ++++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 5 -- MediaBrowser.Controller/Playlists/Playlist.cs | 9 ++++ MediaBrowser.Model/LiveTv/ProgramQuery.cs | 3 ++ .../LiveTv/RecommendedProgramQuery.cs | 9 +++- MediaBrowser.Providers/Manager/MetadataService.cs | 61 +++++++++++++++++++-- .../Music/MusicBrainzArtistProvider.cs | 29 +++++++--- .../Dto/DtoService.cs | 33 ++++-------- .../Library/LibraryManager.cs | 14 +++-- .../LiveTv/EmbyTV/EmbyTV.cs | 18 ++++++- .../LiveTv/LiveTvManager.cs | 10 ++-- .../Persistence/SqliteItemRepository.cs | 62 ++++++++++++++++++++-- .../Sorting/DateLastMediaAddedComparer.cs | 8 +-- .../MediaBrowser.ServerApplication.csproj | 2 - .../Native/WindowsApp.cs | 17 ++++-- .../ffmpeg/ffmpegx64.7z.REMOVED.git-id | 1 - .../ffmpeg/ffmpegx86.7z.REMOVED.git-id | 1 - 31 files changed, 330 insertions(+), 101 deletions(-) delete mode 100644 MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id delete mode 100644 MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 66ca8c25d4..a677bc6004 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -488,13 +488,17 @@ namespace MediaBrowser.Api { try { - Logger.Info("Killing ffmpeg process for {0}", job.Path); + Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path); //process.Kill(); process.StandardInput.WriteLine("q"); // Need to wait because killing is asynchronous - process.WaitForExit(5000); + if (!process.WaitForExit(5000)) + { + Logger.Info("Killing ffmpeg process for {0}", job.Path); + process.Kill(); + } } catch (Exception ex) { diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ebcf8fbeac..d3a4558c88 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -254,6 +254,8 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableImages { get; set; } + public bool EnableTotalRecordCount { 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; } @@ -266,12 +268,24 @@ 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; } + + public GetPrograms() + { + EnableTotalRecordCount = true; + } } [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] [Authenticated] public class GetRecommendedPrograms : IReturn>, IHasDtoOptions { + public bool EnableTotalRecordCount { get; set; } + + public GetRecommendedPrograms() + { + EnableTotalRecordCount = true; + } + [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string UserId { get; set; } @@ -662,7 +676,8 @@ namespace MediaBrowser.Api.LiveTv { ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(), UserId = request.UserId, - HasAired = request.HasAired + HasAired = request.HasAired, + EnableTotalRecordCount = request.EnableTotalRecordCount }; if (!string.IsNullOrEmpty(request.MinStartDate)) @@ -709,7 +724,8 @@ namespace MediaBrowser.Api.LiveTv HasAired = request.HasAired, IsMovie = request.IsMovie, IsKids = request.IsKids, - IsSports = request.IsSports + IsSports = request.IsSports, + EnableTotalRecordCount = request.EnableTotalRecordCount }; var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 9590971d06..786615cc3e 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -196,7 +196,6 @@ namespace MediaBrowser.Api.Movies var parentIds = new string[] { }; var list = _libraryManager.GetItemList(query, parentIds) - .DistinctBy(i => i.PresentationUniqueKey, StringComparer.OrdinalIgnoreCase) .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) .ToList(); diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 6867f6308c..aee1a8d545 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -12,6 +12,7 @@ namespace MediaBrowser.Api.UserLibrary protected BaseItemsRequest() { EnableImages = true; + EnableTotalRecordCount = true; } /// @@ -104,7 +105,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsInBoxSet { get; set; } - + + public bool EnableTotalRecordCount { get; set; } + /// /// Skips over a given number of items within the results. Use for paging. /// diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 7d2029cabe..ff937078e6 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -230,7 +230,8 @@ namespace MediaBrowser.Api.UserLibrary ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId), ParentIndexNumber = request.ParentIndexNumber, AiredDuringSeason = request.AiredDuringSeason, - AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater + AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater, + EnableTotalRecordCount = request.EnableTotalRecordCount }; if (!string.IsNullOrWhiteSpace(request.Ids)) diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index fd56a6746a..c34a884ff5 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -40,12 +40,6 @@ namespace MediaBrowser.Controller.Entities.Audio public List AlbumArtists { get; set; } - /// - /// Gets or sets the album. - /// - /// The album. - public string Album { get; set; } - [IgnoreDataMember] public bool IsThemeMedia { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 5cb4e8c9d1..615276e837 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + [IgnoreDataMember] public List AllArtists { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 6f6f124dbb..6104976615 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -34,6 +34,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 2e968c8803..cd021d2ab5 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -69,6 +69,12 @@ namespace MediaBrowser.Controller.Entities public List ImageInfos { get; set; } + /// + /// Gets or sets the album. + /// + /// The album. + public string Album { get; set; } + /// /// Gets or sets the channel identifier. /// @@ -1175,6 +1181,11 @@ namespace MediaBrowser.Controller.Entities get { return Id.ToString("N"); } } + public virtual bool RequiresRefresh() + { + return false; + } + private string _userDataKey; /// /// Gets the user data key. diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 978fd7fedf..457a0b3abd 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -28,6 +28,9 @@ namespace MediaBrowser.Controller.Entities public List ThemeSongIds { get; set; } public List ThemeVideoIds { get; set; } + [IgnoreDataMember] + public DateTime? DateLastMediaAdded { get; set; } + public Folder() { LinkedChildren = new List(); @@ -55,6 +58,36 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool SupportsCumulativeRunTimeTicks + { + get + { + return false; + } + } + + [IgnoreDataMember] + public virtual bool SupportsDateLastMediaAdded + { + get + { + return false; + } + } + + public override bool RequiresRefresh() + { + var baseResult = base.RequiresRefresh(); + + if (SupportsCumulativeRunTimeTicks && !RunTimeTicks.HasValue) + { + baseResult = true; + } + + return baseResult; + } + [IgnoreDataMember] public override string FileNameWithoutExtension { @@ -789,11 +822,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder"); return true; } - if (query.SortBy.Contains(ItemSortBy.Album, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.Album"); - return true; - } if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist"); @@ -809,11 +837,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget"); return true; } - if (query.SortBy.Contains(ItemSortBy.DateLastContentAdded, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.DateLastContentAdded"); - return true; - } if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem"); @@ -1086,12 +1109,6 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.AlbumNames.Length > 0) - { - Logger.Debug("Query requires post-filtering due to AlbumNames"); - return true; - } - if (query.ArtistNames.Length > 0) { Logger.Debug("Query requires post-filtering due to ArtistNames"); diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 1f680b35f3..c7940c8a97 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -49,5 +49,7 @@ namespace MediaBrowser.Controller.Entities /// /// true if [supports people]; otherwise, false. bool SupportsPeople { get; } + + bool RequiresRefresh(); } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 385ee81e9d..5236b0a278 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -137,10 +137,12 @@ namespace MediaBrowser.Controller.Entities public string AncestorWithPresentationUniqueKey { get; set; } public bool GroupByPresentationUniqueKey { get; set; } + public bool EnableTotalRecordCount { get; set; } public InternalItemsQuery() { GroupByPresentationUniqueKey = true; + EnableTotalRecordCount = true; AlbumNames = new string[] { }; ArtistNames = new string[] { }; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index bf4c2559c5..7119828e26 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -9,12 +9,6 @@ namespace MediaBrowser.Controller.Entities { public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo { - /// - /// Gets or sets the album. - /// - /// The album. - public string Album { get; set; } - /// /// Gets or sets the budget. /// diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 4e6128527c..ac8cc0ee26 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -32,6 +32,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsDateLastMediaAdded + { + get + { + return true; + } + } + [IgnoreDataMember] public override Guid? DisplayParentId { diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 680af1843c..f8cdab8ce6 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsDateLastMediaAdded + { + get + { + return true; + } + } + public bool DisplaySpecialsWithSeasons { get; set; } public List LocalTrailerIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 8ce39c6979..b9e997d175 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -102,10 +102,5 @@ namespace MediaBrowser.Controller.Entities LibraryManager.RegisterItem(item); } } - - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) - { - // Nothing meaninful here and will only waste resources - } } } diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index cd0c5dc1c7..003cbcfcda 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -39,6 +39,15 @@ namespace MediaBrowser.Controller.Playlists } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + public override bool IsAuthorizedToDelete(User user) { return true; diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 7a877e3561..0141191c18 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -14,8 +14,11 @@ namespace MediaBrowser.Model.LiveTv ChannelIds = new string[] { }; SortBy = new string[] { }; Genres = new string[] { }; + EnableTotalRecordCount = true; } + public bool EnableTotalRecordCount { get; set; } + /// /// Fields to return within the items, in addition to basic information /// diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index e83a8fda65..0e6d081a1d 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -13,7 +13,14 @@ namespace MediaBrowser.Model.LiveTv public bool? EnableImages { get; set; } public int? ImageTypeLimit { get; set; } public ImageType[] EnableImageTypes { get; set; } - + + public bool EnableTotalRecordCount { get; set; } + + public RecommendedProgramQuery() + { + EnableTotalRecordCount = true; + } + /// /// Gets or sets the user identifier. /// diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index ae48c996a0..218127ab9e 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -310,6 +310,11 @@ namespace MediaBrowser.Providers.Manager return true; } + if (item is MusicVideo) + { + return true; + } + return false; } @@ -390,7 +395,6 @@ namespace MediaBrowser.Providers.Manager return _cachedTask; } - private readonly Task _cachedResult = Task.FromResult(ItemUpdateType.None); /// /// Befores the save. /// @@ -398,9 +402,58 @@ namespace MediaBrowser.Providers.Manager /// if set to true [is full refresh]. /// Type of the current update. /// ItemUpdateType. - protected virtual Task BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected virtual async Task BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = ItemUpdateType.None; + + updateType |= SaveCumulativeRunTimeTicks(item, isFullRefresh, currentUpdateType); + updateType |= SaveDateLastMediaAdded(item, isFullRefresh, currentUpdateType); + + return updateType; + } + + private ItemUpdateType SaveCumulativeRunTimeTicks(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = ItemUpdateType.None; + + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + var folder = item as Folder; + if (folder != null && folder.SupportsCumulativeRunTimeTicks) + { + var ticks = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.RunTimeTicks ?? 0).Sum(); + + if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks) + { + folder.RunTimeTicks = ticks; + updateType = ItemUpdateType.MetadataEdit; + } + } + } + + return updateType; + } + + private ItemUpdateType SaveDateLastMediaAdded(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - return _cachedResult; + var updateType = ItemUpdateType.None; + + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + var folder = item as Folder; + if (folder != null && folder.SupportsDateLastMediaAdded) + { + var date = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).Max(); + + if (!folder.DateLastMediaAdded.HasValue || folder.DateLastMediaAdded.Value != date) + { + folder.DateLastMediaAdded = date; + updateType = ItemUpdateType.MetadataEdit; + } + } + } + + return updateType; } /// @@ -420,7 +473,7 @@ namespace MediaBrowser.Providers.Manager : status.DateLastMetadataRefresh ?? default(DateTime); // Run all if either of these flags are true - var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime); + var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || item.RequiresRefresh(); if (!runAllProviders) { diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index ad900123ed..2eb65f4e57 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -62,12 +62,25 @@ namespace MediaBrowser.Providers.Music private IEnumerable GetResultsFromResponse(XmlDocument doc) { - var ns = new XmlNamespaceManager(doc.NameTable); - ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#"); + //var ns = new XmlNamespaceManager(doc.NameTable); + //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#"); var list = new List(); - var nodes = doc.SelectNodes("//mb:artist-list/mb:artist", ns); + var docElem = doc.DocumentElement; + + if (docElem == null) + { + return list; + } + + var artistList = docElem.FirstChild; + if (artistList == null) + { + return list; + } + + var nodes = artistList.ChildNodes; if (nodes != null) { @@ -79,11 +92,13 @@ namespace MediaBrowser.Providers.Music string mbzId = node.Attributes["id"].Value; - var nameNode = node.SelectSingleNode("//mb:name", ns); - - if (nameNode != null) + foreach (var child in node.ChildNodes.Cast()) { - name = nameNode.InnerText; + if (string.Equals(child.Name, "name", StringComparison.OrdinalIgnoreCase)) + { + name = node.InnerText; + break; + } } if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name)) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 0aec3230da..32610a6ad9 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -499,6 +499,16 @@ namespace MediaBrowser.Server.Implementations.Dto } } + if (fields.Contains(ItemFields.CumulativeRunTimeTicks)) + { + dto.CumulativeRunTimeTicks = dto.RunTimeTicks; + } + + if (fields.Contains(ItemFields.DateLastMediaAdded)) + { + dto.DateLastMediaAdded = folder.DateLastMediaAdded; + } + dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100; } @@ -1613,9 +1623,7 @@ namespace MediaBrowser.Server.Implementations.Dto { var recursiveItemCount = 0; var unplayed = 0; - long runtime = 0; - DateTime? dateLastMediaAdded = null; double totalPercentPlayed = 0; double totalSyncPercent = 0; var addSyncInfo = fields.Contains(ItemFields.SyncInfo); @@ -1632,15 +1640,6 @@ namespace MediaBrowser.Server.Implementations.Dto // Loop through each recursive child foreach (var child in children) { - if (!dateLastMediaAdded.HasValue) - { - dateLastMediaAdded = child.DateCreated; - } - else - { - dateLastMediaAdded = new[] { dateLastMediaAdded.Value, child.DateCreated }.Max(); - } - var userdata = _userDataRepository.GetUserData(user, child); recursiveItemCount++; @@ -1669,8 +1668,6 @@ namespace MediaBrowser.Server.Implementations.Dto unplayed++; } - runtime += child.RunTimeTicks ?? 0; - if (addSyncInfo) { double percent = 0; @@ -1709,16 +1706,6 @@ namespace MediaBrowser.Server.Implementations.Dto } } } - - if (runtime > 0 && fields.Contains(ItemFields.CumulativeRunTimeTicks)) - { - dto.CumulativeRunTimeTicks = runtime; - } - - if (fields.Contains(ItemFields.DateLastMediaAdded)) - { - dto.DateLastMediaAdded = dateLastMediaAdded; - } } /// diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index f9bf3446f4..c95b301722 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1354,12 +1354,20 @@ namespace MediaBrowser.Server.Implementations.Library AddUserToQuery(query, query.User); } - var initialResult = ItemRepository.GetItemIds(query); + if (query.EnableTotalRecordCount) + { + var initialResult = ItemRepository.GetItemIds(query); + + return new QueryResult + { + TotalRecordCount = initialResult.TotalRecordCount, + Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray() + }; + } return new QueryResult { - TotalRecordCount = initialResult.TotalRecordCount, - Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray() + Items = ItemRepository.GetItemIdsList(query).Select(GetItemById).Where(i => i != null).ToArray() }; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c5920d3d6a..b5e8ad79a5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -760,7 +760,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (info.IsMovie) { var customRecordingPath = config.MovieRecordingPath; - if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + var allowSubfolder = true; + if (!string.IsNullOrWhiteSpace(customRecordingPath)) + { + allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase); + recordPath = customRecordingPath; + } + + if (allowSubfolder && config.EnableRecordingSubfolders) { recordPath = Path.Combine(recordPath, "Movies"); } @@ -775,7 +782,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV else if (info.IsSeries) { var customRecordingPath = config.SeriesRecordingPath; - if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + var allowSubfolder = true; + if (!string.IsNullOrWhiteSpace(customRecordingPath)) + { + allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase); + recordPath = customRecordingPath; + } + + if (allowSubfolder && config.EnableRecordingSubfolders) { recordPath = Path.Combine(recordPath, "Series"); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index eec8328f89..175eed66c0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -886,7 +886,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv StartIndex = query.StartIndex, Limit = query.Limit, SortBy = query.SortBy, - SortOrder = query.SortOrder ?? SortOrder.Ascending + SortOrder = query.SortOrder ?? SortOrder.Ascending, + EnableTotalRecordCount = query.EnableTotalRecordCount }; if (query.HasAired.HasValue) @@ -924,7 +925,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsAiring = query.IsAiring, IsMovie = query.IsMovie, IsSports = query.IsSports, - IsKids = query.IsKids + IsKids = query.IsKids, + EnableTotalRecordCount = query.EnableTotalRecordCount }; if (query.HasAired.HasValue) @@ -1263,11 +1265,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv private async Task CleanDatabaseInternal(List currentIdList, string[] validTypes, IProgress progress, CancellationToken cancellationToken) { - var list = _itemRepo.GetItemIds(new InternalItemsQuery + var list = _itemRepo.GetItemIdsList(new InternalItemsQuery { IncludeItemTypes = validTypes - }).Items.ToList(); + }).ToList(); var numComplete = 0; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 09739f8a9d..180bd35479 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 76; + public const int LatestSchemaVersion = 77; /// /// Initializes a new instance of the class. @@ -235,6 +235,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); + _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); string[] postQueries = @@ -351,7 +354,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "TrailerTypes", "DateModifiedDuringLastRefresh", "OriginalTitle", - "PrimaryVersionId" + "PrimaryVersionId", + "DateLastMediaAdded", + "Album" }; private readonly string[] _mediaStreamSaveColumns = @@ -463,7 +468,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "PresentationUniqueKey", "SlugName", "OriginalTitle", - "PrimaryVersionId" + "PrimaryVersionId", + "DateLastMediaAdded", + "Album" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -824,6 +831,18 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = null; } + var folder = item as Folder; + if (folder != null && folder.DateLastMediaAdded.HasValue) + { + _saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.Album; + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -1217,6 +1236,17 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + var folder = item as Folder; + if (folder != null && !reader.IsDBNull(54)) + { + folder.DateLastMediaAdded = reader.GetDateTime(54).ToUniversalTime(); + } + + if (!reader.IsDBNull(55)) + { + item.Album = reader.GetString(55); + } + return item; } @@ -1777,6 +1807,10 @@ namespace MediaBrowser.Server.Implementations.Persistence { return new Tuple("played", false); } + if (string.Equals(name, ItemSortBy.DateLastContentAdded, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("DateLastMediaAdded", false); + } return new Tuple(name, false); } @@ -2484,7 +2518,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (query.MediaTypes.Length == 1) { whereClauses.Add("MediaType=@MediaTypes"); - cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0].ToString(); + cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0]; } if (query.MediaTypes.Length > 1) { @@ -2493,6 +2527,26 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("MediaType in (" + val + ")"); } + if (query.AlbumNames.Length > 0) + { + var clause = "("; + + var index = 0; + foreach (var name in query.AlbumNames) + { + if (index > 0) + { + clause += " OR "; + } + clause += "Album=@AlbumName" + index; + index++; + cmd.Parameters.Add(cmd, "@AlbumName" + index, DbType.String).Value = name; + } + + clause += ")"; + whereClauses.Add(clause); + } + //var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0; var enableItemsByName = query.IncludeItemsByName ?? false; diff --git a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs index 68cd44ec94..5c51f5e0fc 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs @@ -49,10 +49,10 @@ namespace MediaBrowser.Server.Implementations.Sorting if (folder != null) { - return folder.GetRecursiveChildren(User, i => !i.IsFolder) - .Select(i => i.DateCreated) - .OrderByDescending(i => i) - .FirstOrDefault(); + if (folder.DateLastMediaAdded.HasValue) + { + return folder.DateLastMediaAdded.Value; + } } return x.DateCreated; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index f544a149d8..366d4b6083 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -142,8 +142,6 @@ - - diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs index 808c7558ec..271b02d9a7 100644 --- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs +++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs @@ -158,9 +158,9 @@ namespace MediaBrowser.ServerApplication.Native info.FFMpegFilename = "ffmpeg.exe"; info.FFProbeFilename = "ffprobe.exe"; - info.Version = "20160401"; + info.Version = "20160508"; info.ArchiveType = "7z"; - info.IsEmbedded = true; + info.IsEmbedded = false; info.DownloadUrls = GetDownloadUrls(); return info; @@ -212,11 +212,18 @@ namespace MediaBrowser.ServerApplication.Native switch (Environment.SystemArchitecture) { case Architecture.X86_X64: - return new[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx64.7z" }; + return new[] + { + "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160508-win64.7z", + "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20160508-git-caee88d-win64-static.7z" + }; case Architecture.X86: - return new[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx86.7z" }; + return new[] + { + "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160508-win32.7z", + "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20160508-git-caee88d-win32-static.7z" + }; } - return new string[] { }; } } diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id deleted file mode 100644 index b0542b75f3..0000000000 --- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -9dc10b022537738edce7eb71aa8dd4adbfee2c7b \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id deleted file mode 100644 index 3939ec44d6..0000000000 --- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -00fa1afa35fbd0a7e97ad7956e42ae17f6882f64 \ No newline at end of file -- cgit v1.2.3 From f54a0da88e12b8b86c70c7de51d6d8fa24366b31 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 20 May 2016 11:57:07 -0400 Subject: better cleanup of recording libraries --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 3 +++ .../LiveTv/EmbyTV/EmbyTV.cs | 30 +++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 4211fbd59f..e00443d191 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -20,12 +20,15 @@ namespace MediaBrowser.Model.LiveTv public int PrePaddingSeconds { get; set; } public int PostPaddingSeconds { get; set; } + public string[] MediaLocationsCreated { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; EnableRecordingSubfolders = true; TunerHosts = new List(); ListingProviders = new List(); + MediaLocationsCreated = new string[] { }; } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2de51479f2..de75aac9cd 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -115,17 +115,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var recordingFolders = GetRecordingFolders(); - var defaultRecordingPath = DefaultRecordingPath; - if (!recordingFolders.Any(i => i.Locations.Contains(defaultRecordingPath, StringComparer.OrdinalIgnoreCase))) - { - RemovePathFromLibrary(defaultRecordingPath); - } - var virtualFolders = _libraryManager.GetVirtualFolders() .ToList(); var allExistingPaths = virtualFolders.SelectMany(i => i.Locations).ToList(); + var pathsAdded = new List(); + foreach (var recordingFolder in recordingFolders) { var pathsToCreate = recordingFolder.Locations @@ -145,11 +141,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { _logger.ErrorException("Error creating virtual folder", ex); } + + pathsAdded.AddRange(pathsToCreate); + } + + var config = GetConfiguration(); + + var pathsToRemove = config.MediaLocationsCreated + .Except(recordingFolders.SelectMany(i => i.Locations)) + .ToList(); + + if (pathsAdded.Count > 0 || pathsToRemove.Count > 0) + { + pathsAdded.InsertRange(0, config.MediaLocationsCreated); + config.MediaLocationsCreated = pathsAdded.Except(pathsToRemove).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + _config.SaveConfiguration("livetv", config); + } + + foreach (var path in pathsToRemove) + { + RemovePathFromLibrary(path); } } private void RemovePathFromLibrary(string path) { + _logger.Debug("Removing path from library: {0}", path); + var requiresRefresh = false; var virtualFolders = _libraryManager.GetVirtualFolders() .ToList(); -- cgit v1.2.3 From 3aea4f7ffcbbbb17d0c9cc07148fdb3a9dad9d5f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 3 Jun 2016 15:32:10 -0400 Subject: add tv genre configuration options --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 11 +++++++++++ MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 6 ++++++ Nuget/MediaBrowser.Common.Internal.nuspec | 4 ++-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 ++-- 5 files changed, 22 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index a59b5f351d..d5290959d5 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -439,6 +439,12 @@ namespace MediaBrowser.Api.LiveTv public string Id { get; set; } } + [Route("/LiveTv/ListingProviders/Default", "GET")] + [Authenticated(AllowBeforeStartupWizard = true)] + public class GetDefaultListingProvider : ListingsProviderInfo, IReturn + { + } + [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")] [Authenticated(AllowBeforeStartupWizard = true)] public class AddListingProvider : ListingsProviderInfo, IReturn @@ -525,6 +531,11 @@ namespace MediaBrowser.Api.LiveTv _dtoService = dtoService; } + public object Get(GetDefaultListingProvider request) + { + return ToOptimizedResult(new ListingsProviderInfo()); + } + public async Task Get(GetSatChannnelScanResult request) { var result = await _liveTvManager.GetSatChannelScanResult(request, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index e00443d191..9e34ff0426 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -73,9 +73,15 @@ namespace MediaBrowser.Model.LiveTv public string[] EnabledTuners { get; set; } public bool EnableAllTuners { get; set; } + public string[] NewsGenres { get; set; } + public string[] SportsGenres { get; set; } + public string[] KidsGenres { get; set; } public ListingsProviderInfo() { + NewsGenres = new string[] { "news" }; + SportsGenres = new string[] { "sports", "basketball", "baseball", "football" }; + KidsGenres = new string[] { "kids", "family", "children" }; EnabledTuners = new string[] { }; EnableAllTuners = true; } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 9d219806c9..a8ef269322 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.649 + 3.0.650 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 2683c42bc8..2bf899ad60 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.649 + 3.0.650 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index c8f164b383..3fdeeaf538 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.649 + 3.0.650 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 d10a5042f68c7f9f72a48af05225b72284a28a6c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 5 Jun 2016 16:41:44 -0400 Subject: update LiveTvOptions --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 9e34ff0426..bcc957df29 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -73,15 +73,17 @@ namespace MediaBrowser.Model.LiveTv public string[] EnabledTuners { get; set; } public bool EnableAllTuners { get; set; } - public string[] NewsGenres { get; set; } - public string[] SportsGenres { get; set; } - public string[] KidsGenres { get; set; } + public string[] NewsCategories { get; set; } + public string[] SportsCategories { get; set; } + public string[] KidsCategories { get; set; } + public string[] MovieCategories { get; set; } public ListingsProviderInfo() { - NewsGenres = new string[] { "news" }; - SportsGenres = new string[] { "sports", "basketball", "baseball", "football" }; - KidsGenres = new string[] { "kids", "family", "children" }; + NewsCategories = new string[] { "news" }; + SportsCategories = new string[] { "sports", "basketball", "baseball", "football" }; + KidsCategories = new string[] { "kids", "family", "children" }; + MovieCategories = new string[] { "movie" }; EnabledTuners = new string[] { }; EnableAllTuners = true; } -- cgit v1.2.3 From 7388320d96a12044f367bf3f1e5e6e31c1904608 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 5 Jun 2016 17:08:55 -0400 Subject: update xmltv --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 4 ++-- .../LiveTv/Listings/XmlTvListingsProvider.cs | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index bcc957df29..33f63e3eb2 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -80,9 +80,9 @@ namespace MediaBrowser.Model.LiveTv public ListingsProviderInfo() { - NewsCategories = new string[] { "news" }; + NewsCategories = new string[] { "news", "journalism", "documentary", "current affairs" }; SportsCategories = new string[] { "sports", "basketball", "baseball", "football" }; - KidsCategories = new string[] { "kids", "family", "children" }; + KidsCategories = new string[] { "kids", "family", "children", "childrens", "disney" }; MovieCategories = new string[] { "movie" }; EnabledTuners = new string[] { }; EnableAllTuners = true; diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index ac741a7d2d..a713ff0ef0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -15,12 +15,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings public class XmlTvListingsProvider : IListingsProvider { private string _language = null; - private Dictionary> _categoryMappings = new Dictionary>(){ - { "Movie", new List() { "Movie", "Film" } }, - //{ "Sports", new List() { "Sports", "Football", "Rugby", "Soccer" } }, - //{ "Kids", new List() { "Childrens", "Children", "Kids", "Disney" } }, - //{ "News", new List() { "News", "Journalism", "Documentary", "Current Affairs" } }, - }; private Dictionary _channelMappings = new Dictionary(){ { "1", "UK_RT_2667" }, -- cgit v1.2.3 From 83105f5aaeea7af09154f6c765b414393740f00d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 6 Jun 2016 14:22:42 -0400 Subject: stubbed out channel mappings --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 3 +++ .../LiveTv/EmbyTV/EmbyTV.cs | 23 +++++++++++++++++++++- .../LiveTv/Listings/XmlTvListingsProvider.cs | 13 ------------ 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 33f63e3eb2..0e44980df2 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Model.LiveTv { @@ -77,6 +78,7 @@ namespace MediaBrowser.Model.LiveTv public string[] SportsCategories { get; set; } public string[] KidsCategories { get; set; } public string[] MovieCategories { get; set; } + public NameValuePair[] ChannelMappings { get; set; } public ListingsProviderInfo() { @@ -86,6 +88,7 @@ namespace MediaBrowser.Model.LiveTv MovieCategories = new string[] { "movie" }; EnabledTuners = new string[] { }; EnableAllTuners = true; + ChannelMappings = new NameValuePair[] {}; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 6e5e8298f9..41c137c295 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -625,7 +625,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _logger.Debug("Getting programs for channel {0}-{1} from {2}-{3}", channel.Number, channel.Name, provider.Item1.Name, provider.Item2.ListingsId ?? string.Empty); - var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, channel.Name, startDateUtc, endDateUtc, cancellationToken) + var channelMappings = GetChannelMappings(provider.Item2); + var channelNumber = channel.Number; + string mappedChannelNumber; + if (channelMappings.TryGetValue(channelNumber, out mappedChannelNumber)) + { + _logger.Debug("Found mapped channel on provider {0}. Tuner channel number: {1}, Mapped channel number: {2}", provider.Item1.Name, channelNumber, mappedChannelNumber); + channelNumber = mappedChannelNumber; + } + + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken) .ConfigureAwait(false); var list = programs.ToList(); @@ -647,6 +656,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return new List(); } + private Dictionary GetChannelMappings(ListingsProviderInfo info) + { + var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var mapping in info.ChannelMappings) + { + dict[mapping.Name] = mapping.Value; + } + + return dict; + } + private List> GetListingProviders() { return GetConfiguration().ListingProviders diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 4f43d93b70..5b0b2ad84b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -17,14 +17,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { private readonly IServerConfigurationManager _config; - private Dictionary _channelMappings = new Dictionary(){ - { "1", "UK_RT_2667" }, - { "2", "UK_RT_116" }, - { "3", "UK_RT_2118" }, - { "4", "UK_RT_2056" }, - { "5", "UK_RT_134" } - }; - public XmlTvListingsProvider(IServerConfigurationManager config) { _config = config; @@ -51,11 +43,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var reader = new XmlTvReader(info.Path, GetLanguage(), null); string mappedChannel = channelNumber; - if (_channelMappings.ContainsKey(channelNumber)) - { - mappedChannel = _channelMappings[channelNumber]; - } - var results = reader.GetProgrammes(mappedChannel, startDateUtc, endDateUtc, cancellationToken); return Task.FromResult(results.Select(p => new ProgramInfo() { -- cgit v1.2.3 From 2538889943c19439f9f87f1daeee6c5ecfcfa244 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 8 Jun 2016 00:57:03 -0400 Subject: add mappings to add meta data method --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 13 +++++++++++++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 6 ++++-- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 0e44980df2..242a2d24e4 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Extensions; namespace MediaBrowser.Model.LiveTv { @@ -90,5 +91,17 @@ namespace MediaBrowser.Model.LiveTv EnableAllTuners = true; ChannelMappings = new NameValuePair[] {}; } + + public string GetMappedChannel(string channelNumber) + { + foreach (NameValuePair mapping in ChannelMappings) + { + if (StringHelper.EqualsIgnoreCase(mapping.Name, channelNumber)) + { + return mapping.Value; + } + } + return channelNumber; + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 41c137c295..d3e5bc1f9e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1000,7 +1000,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV result.Item3.Release(); } - _libraryMonitor.ReportFileSystemChangeComplete(recordPath, false); + _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true); } } catch (OperationCanceledException) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 328dd99792..4de029d570 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -107,11 +107,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var reader = new XmlTvReader(info.Path, GetLanguage(), null); var results = reader.GetChannels().ToList(); - if (channels != null && channels.Count > 0) + if (channels != null) { channels.ForEach(c => { - var match = results.FirstOrDefault(r => r.Id == c.Id); + var channelNumber = info.GetMappedChannel(c.Number); + var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase)); + if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source)) { c.ImageUrl = match.Icon.Source; -- cgit v1.2.3 From f58a9194881f0c76ecc16a24c189c7aaa74e86f4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 19 Jun 2016 13:41:49 -0400 Subject: improve display of active recordings --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 5 ++++- MediaBrowser.Model/LiveTv/TimerQuery.cs | 2 ++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 3 +++ MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 12 ++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 48f7cd62e7..074dba7c58 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -200,6 +200,8 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by timers belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string SeriesTimerId { get; set; } + + public bool? IsActive { get; set; } } [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] @@ -927,7 +929,8 @@ namespace MediaBrowser.Api.LiveTv var result = await _liveTvManager.GetTimers(new TimerQuery { ChannelId = request.ChannelId, - SeriesTimerId = request.SeriesTimerId + SeriesTimerId = request.SeriesTimerId, + IsActive = request.IsActive }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs index e6ceff5300..87b6b89acd 100644 --- a/MediaBrowser.Model/LiveTv/TimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs @@ -13,5 +13,7 @@ /// /// The series timer identifier. public string SeriesTimerId { get; set; } + + public bool? IsActive { 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 d38e9ad321..1b43ff7c19 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1010,6 +1010,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV Action onStarted = () => { + timer.Status = RecordingStatus.InProgress; + _timerProvider.AddOrUpdate(timer); + result.Item3.Release(); isResourceOpen = false; }; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 552139b4ac..9f80877f63 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1665,6 +1665,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv var results = await Task.WhenAll(tasks).ConfigureAwait(false); var timers = results.SelectMany(i => i.ToList()); + if (query.IsActive.HasValue) + { + if (query.IsActive.Value) + { + timers = timers.Where(i => i.Item1.Status == RecordingStatus.InProgress); + } + else + { + timers = timers.Where(i => i.Item1.Status != RecordingStatus.InProgress); + } + } + if (!string.IsNullOrEmpty(query.ChannelId)) { var guid = new Guid(query.ChannelId); -- cgit v1.2.3 From c05f0bea04460b33661f69658ac8e72406cb3ad1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Jun 2016 13:07:53 -0400 Subject: update live tv queries --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 10 +++++++++- MediaBrowser.Model/LiveTv/RecordingQuery.cs | 7 +++++++ MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 9 ++++++++- .../Persistence/SqliteItemRepository.cs | 11 +++++++++-- 4 files changed, 33 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 074dba7c58..784057b32e 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -146,6 +146,13 @@ 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; } + + public bool EnableTotalRecordCount { get; set; } + + public GetRecordings() + { + EnableTotalRecordCount = true; + } } [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")] @@ -898,7 +905,8 @@ namespace MediaBrowser.Api.LiveTv Limit = request.Limit, Status = request.Status, SeriesTimerId = request.SeriesTimerId, - IsInProgress = request.IsInProgress + IsInProgress = request.IsInProgress, + EnableTotalRecordCount = request.EnableTotalRecordCount }, options, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index 0cf9976025..923d303f80 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -70,5 +70,12 @@ namespace MediaBrowser.Model.LiveTv public bool? EnableImages { get; set; } public int? ImageTypeLimit { get; set; } public ImageType[] EnableImageTypes { get; set; } + + public bool EnableTotalRecordCount { get; set; } + + public RecordingQuery() + { + EnableTotalRecordCount = true; + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 29c4a43d38..95ed2aac1a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -896,6 +896,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + if (query.SortBy.Length == 0) + { + // Unless something else was specified, order by start date to take advantage of a specialized index + query.SortBy = new[] { ItemSortBy.StartDate }; + } + var internalQuery = new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, @@ -1414,7 +1420,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExcludeLocationTypes = new[] { LocationType.Virtual }, Limit = Math.Min(200, query.Limit ?? int.MaxValue), SortBy = new[] { ItemSortBy.DateCreated }, - SortOrder = SortOrder.Descending + SortOrder = SortOrder.Descending, + EnableTotalRecordCount = query.EnableTotalRecordCount }); } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index ed5a64b8c8..006cb2edf0 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -162,7 +162,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT, CleanValue TEXT)", //"create index if not exists idx_ItemValues on ItemValues(ItemId)", "create index if not exists idx_ItemValues2 on ItemValues(ItemId,Type)", - "create index if not exists idx_ItemValues3 on ItemValues(ItemId,Type,CleanValue)", "create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT, PRIMARY KEY (ItemId, Name))", "create index if not exists Idx_ProviderIds on ProviderIds(ItemId)", @@ -276,6 +275,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)", "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)", + // live tv programs + "create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)", + // used by movie suggestions "create index if not exists idx_TypeTopParentIdGroup on TypedBaseItems(Type,TopParentId,PresentationUniqueKey)", "create index if not exists idx_TypeTopParentId2 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem)", @@ -286,8 +288,13 @@ namespace MediaBrowser.Server.Implementations.Persistence // latest items "create index if not exists idx_TypeTopParentId9 on TypedBaseItems(TopParentId,Type,IsVirtualItem,PresentationUniqueKey,DateCreated)", + "create index if not exists idx_TypeTopParentId8 on TypedBaseItems(TopParentId,IsFolder,IsVirtualItem,PresentationUniqueKey,DateCreated)", + + // resume "create index if not exists idx_TypeTopParentId7 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem,PresentationUniqueKey)", - "create index if not exists idx_TypeTopParentId8 on TypedBaseItems(TopParentId,IsFolder,IsVirtualItem,PresentationUniqueKey)" + + // items by name + "create index if not exists idx_ItemValues3 on ItemValues(ItemId,Type,CleanValue)" }; _connection.RunQueries(postQueries, Logger); -- cgit v1.2.3 From 78e6c638bcbd4781221804fb8eef4c34fb4cb881 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 15 Jul 2016 15:53:28 -0400 Subject: remove fody from build --- MediaBrowser.Model.Portable/FodyWeavers.xml | 3 +-- .../MediaBrowser.Model.Portable.csproj | 12 ++---------- MediaBrowser.Model.Portable/packages.config | 5 ----- MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj | 3 --- MediaBrowser.Model/Dto/BaseItemDto.cs | 7 +------ MediaBrowser.Model/Dto/BaseItemPerson.cs | 10 ++-------- MediaBrowser.Model/Dto/ChapterInfoDto.cs | 8 ++------ MediaBrowser.Model/Dto/UserDto.cs | 8 +------- MediaBrowser.Model/Dto/UserItemDataDto.cs | 7 ++----- MediaBrowser.Model/Entities/DisplayPreferences.cs | 9 +-------- MediaBrowser.Model/Extensions/IHasPropertyChangedEvent.cs | 8 -------- MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs | 9 +-------- MediaBrowser.Model/LiveTv/ChannelInfoDto.cs | 5 +---- MediaBrowser.Model/MediaBrowser.Model.csproj | 1 - MediaBrowser.Model/Session/SessionInfoDto.cs | 5 +---- 15 files changed, 15 insertions(+), 85 deletions(-) delete mode 100644 MediaBrowser.Model.Portable/packages.config delete mode 100644 MediaBrowser.Model/Extensions/IHasPropertyChangedEvent.cs (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model.Portable/FodyWeavers.xml b/MediaBrowser.Model.Portable/FodyWeavers.xml index 7369928101..6e2fa02e64 100644 --- a/MediaBrowser.Model.Portable/FodyWeavers.xml +++ b/MediaBrowser.Model.Portable/FodyWeavers.xml @@ -1,4 +1,3 @@ - + - \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 0de9fb519c..862d95f7ee 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -36,6 +36,8 @@ false true true + + true @@ -617,9 +619,6 @@ Extensions\FloatHelper.cs - - Extensions\IHasPropertyChangedEvent.cs - Extensions\IntHelper.cs @@ -1233,13 +1232,6 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - -