diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs deleted file mode 100644 index 7dbeaf6b7..000000000 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ /dev/null @@ -1,634 +0,0 @@ -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Logging; -using Microsoft.Win32; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using CommonIO; -using MediaBrowser.Controller; - -namespace MediaBrowser.Server.Implementations.IO -{ - public class LibraryMonitor : ILibraryMonitor - { - /// - /// The file system watchers - /// - private readonly ConcurrentDictionary _fileSystemWatchers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - /// - /// The affected paths - /// - private readonly List _activeRefreshers = new List(); - - /// - /// A dynamic list of paths that should be ignored. Added to during our own file sytem modifications. - /// - private readonly ConcurrentDictionary _tempIgnoredPaths = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Any file name ending in any of these will be ignored by the watchers - /// - private readonly IReadOnlyList _alwaysIgnoreFiles = new List - { - "small.jpg", - "albumart.jpg", - - // WMC temp recording directories that will constantly be written to - "TempRec", - "TempSBE" - }; - - private readonly IReadOnlyList _alwaysIgnoreSubstrings = new List - { - // Synology - "eaDir", - "#recycle", - ".wd_tv", - ".actors" - }; - - private readonly IReadOnlyList _alwaysIgnoreExtensions = new List - { - // thumbs.db - ".db", - - // bts sync files - ".bts", - ".sync" - }; - - /// - /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope. - /// - /// The path. - private void TemporarilyIgnore(string path) - { - _tempIgnoredPaths[path] = path; - } - - public void ReportFileSystemChangeBeginning(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - TemporarilyIgnore(path); - } - - public bool IsPathLocked(string path) - { - var lockedPaths = _tempIgnoredPaths.Keys.ToList(); - return lockedPaths.Any(i => string.Equals(i, path, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(i, path)); - } - - public async void ReportFileSystemChangeComplete(string path, bool refreshPath) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - // This is an arbitraty amount of time, but delay it because file system writes often trigger events long after the file was actually written to. - // Seeing long delays in some situations, especially over the network, sometimes up to 45 seconds - // But if we make this delay too high, we risk missing legitimate changes, such as user adding a new file, or hand-editing metadata - await Task.Delay(45000).ConfigureAwait(false); - - string val; - _tempIgnoredPaths.TryRemove(path, out val); - - if (refreshPath) - { - try - { - ReportFileSystemChanged(path); - } - catch (Exception ex) - { - Logger.ErrorException("Error in ReportFileSystemChanged for {0}", ex, path); - } - } - } - - /// - /// Gets or sets the logger. - /// - /// The logger. - private ILogger Logger { get; set; } - - /// - /// Gets or sets the task manager. - /// - /// The task manager. - private ITaskManager TaskManager { get; set; } - - private ILibraryManager LibraryManager { get; set; } - private IServerConfigurationManager ConfigurationManager { get; set; } - - private readonly IFileSystem _fileSystem; - private readonly IServerApplicationHost _appHost; - - /// - /// Initializes a new instance of the class. - /// - public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IServerApplicationHost appHost) - { - if (taskManager == null) - { - throw new ArgumentNullException("taskManager"); - } - - LibraryManager = libraryManager; - TaskManager = taskManager; - Logger = logManager.GetLogger(GetType().Name); - ConfigurationManager = configurationManager; - _fileSystem = fileSystem; - _appHost = appHost; - - SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; - } - - /// - /// Handles the PowerModeChanged event of the SystemEvents control. - /// - /// The source of the event. - /// The instance containing the event data. - void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) - { - Restart(); - } - - private void Restart() - { - Stop(); - Start(); - } - - private bool IsLibraryMonitorEnabaled(BaseItem item) - { - if (item is BasePluginFolder) - { - return false; - } - - var options = LibraryManager.GetLibraryOptions(item); - - if (options != null) - { - return options.EnableRealtimeMonitor; - } - - return false; - } - - public void Start() - { - LibraryManager.ItemAdded += LibraryManager_ItemAdded; - LibraryManager.ItemRemoved += LibraryManager_ItemRemoved; - - var pathsToWatch = new List { }; - - var paths = LibraryManager - .RootFolder - .Children - .Where(IsLibraryMonitorEnabaled) - .OfType() - .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) - .OrderBy(i => i) - .ToList(); - - foreach (var path in paths) - { - if (!ContainsParentFolder(pathsToWatch, path)) - { - pathsToWatch.Add(path); - } - } - - foreach (var path in pathsToWatch) - { - StartWatchingPath(path); - } - } - - private void StartWatching(BaseItem item) - { - if (IsLibraryMonitorEnabaled(item)) - { - StartWatchingPath(item.Path); - } - } - - /// - /// Handles the ItemRemoved event of the LibraryManager control. - /// - /// The source of the event. - /// The instance containing the event data. - void LibraryManager_ItemRemoved(object sender, ItemChangeEventArgs e) - { - if (e.Item.GetParent() is AggregateFolder) - { - StopWatchingPath(e.Item.Path); - } - } - - /// - /// Handles the ItemAdded event of the LibraryManager control. - /// - /// The source of the event. - /// The instance containing the event data. - void LibraryManager_ItemAdded(object sender, ItemChangeEventArgs e) - { - if (e.Item.GetParent() is AggregateFolder) - { - StartWatching(e.Item); - } - } - - /// - /// Examine a list of strings assumed to be file paths to see if it contains a parent of - /// the provided path. - /// - /// The LST. - /// The path. - /// true if [contains parent folder] [the specified LST]; otherwise, false. - /// path - private static bool ContainsParentFolder(IEnumerable lst, string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException("path"); - } - - path = path.TrimEnd(Path.DirectorySeparatorChar); - - return lst.Any(str => - { - //this should be a little quicker than examining each actual parent folder... - var compare = str.TrimEnd(Path.DirectorySeparatorChar); - - return path.Equals(compare, StringComparison.OrdinalIgnoreCase) || (path.StartsWith(compare, StringComparison.OrdinalIgnoreCase) && path[compare.Length] == Path.DirectorySeparatorChar); - }); - } - - /// - /// Starts the watching path. - /// - /// The path. - private void StartWatchingPath(string path) - { - // Creating a FileSystemWatcher over the LAN can take hundreds of milliseconds, so wrap it in a Task to do them all in parallel - Task.Run(() => - { - try - { - var newWatcher = new FileSystemWatcher(path, "*") - { - IncludeSubdirectories = true - }; - - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - newWatcher.InternalBufferSize = 32767; - } - - newWatcher.NotifyFilter = NotifyFilters.CreationTime | - NotifyFilters.DirectoryName | - NotifyFilters.FileName | - NotifyFilters.LastWrite | - NotifyFilters.Size | - NotifyFilters.Attributes; - - newWatcher.Created += watcher_Changed; - newWatcher.Deleted += watcher_Changed; - newWatcher.Renamed += watcher_Changed; - newWatcher.Changed += watcher_Changed; - - newWatcher.Error += watcher_Error; - - if (_fileSystemWatchers.TryAdd(path, newWatcher)) - { - newWatcher.EnableRaisingEvents = true; - Logger.Info("Watching directory " + path); - } - else - { - Logger.Info("Unable to add directory watcher for {0}. It already exists in the dictionary.", path); - newWatcher.Dispose(); - } - - } - catch (Exception ex) - { - Logger.ErrorException("Error watching path: {0}", ex, path); - } - }); - } - - /// - /// Stops the watching path. - /// - /// The path. - private void StopWatchingPath(string path) - { - FileSystemWatcher watcher; - - if (_fileSystemWatchers.TryGetValue(path, out watcher)) - { - DisposeWatcher(watcher); - } - } - - /// - /// Disposes the watcher. - /// - /// The watcher. - private void DisposeWatcher(FileSystemWatcher watcher) - { - try - { - using (watcher) - { - Logger.Info("Stopping directory watching for path {0}", watcher.Path); - - watcher.EnableRaisingEvents = false; - } - } - catch - { - - } - finally - { - RemoveWatcherFromList(watcher); - } - } - - /// - /// Removes the watcher from list. - /// - /// The watcher. - private void RemoveWatcherFromList(FileSystemWatcher watcher) - { - FileSystemWatcher removed; - - _fileSystemWatchers.TryRemove(watcher.Path, out removed); - } - - /// - /// Handles the Error event of the watcher control. - /// - /// The source of the event. - /// The instance containing the event data. - void watcher_Error(object sender, ErrorEventArgs e) - { - var ex = e.GetException(); - var dw = (FileSystemWatcher)sender; - - Logger.ErrorException("Error in Directory watcher for: " + dw.Path, ex); - - DisposeWatcher(dw); - } - - /// - /// Handles the Changed event of the watcher control. - /// - /// The source of the event. - /// The instance containing the event data. - void watcher_Changed(object sender, FileSystemEventArgs e) - { - try - { - Logger.Debug("Changed detected of type " + e.ChangeType + " to " + e.FullPath); - - var path = e.FullPath; - - // For deletes, use the parent path - if (e.ChangeType == WatcherChangeTypes.Deleted) - { - var parentPath = Path.GetDirectoryName(path); - - if (!string.IsNullOrWhiteSpace(parentPath)) - { - path = parentPath; - } - } - - ReportFileSystemChanged(path); - } - catch (Exception ex) - { - Logger.ErrorException("Exception in ReportFileSystemChanged. Path: {0}", ex, e.FullPath); - } - } - - public void ReportFileSystemChanged(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - var filename = Path.GetFileName(path); - - var monitorPath = !string.IsNullOrEmpty(filename) && - !_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) && - !_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase) && - _alwaysIgnoreSubstrings.All(i => path.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1); - - // Ignore certain files - var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList(); - - // If the parent of an ignored path has a change event, ignore that too - if (tempIgnorePaths.Any(i => - { - if (string.Equals(i, path, StringComparison.OrdinalIgnoreCase)) - { - Logger.Debug("Ignoring change to {0}", path); - return true; - } - - if (_fileSystem.ContainsSubPath(i, path)) - { - Logger.Debug("Ignoring change to {0}", path); - return true; - } - - // Go up a level - var parent = Path.GetDirectoryName(i); - if (!string.IsNullOrEmpty(parent)) - { - if (string.Equals(parent, path, StringComparison.OrdinalIgnoreCase)) - { - Logger.Debug("Ignoring change to {0}", path); - return true; - } - } - - return false; - - })) - { - monitorPath = false; - } - - if (monitorPath) - { - // Avoid implicitly captured closure - CreateRefresher(path); - } - } - - private void CreateRefresher(string path) - { - var parentPath = Path.GetDirectoryName(path); - - lock (_activeRefreshers) - { - var refreshers = _activeRefreshers.ToList(); - foreach (var refresher in refreshers) - { - // Path is already being refreshed - if (string.Equals(path, refresher.Path, StringComparison.Ordinal)) - { - refresher.RestartTimer(); - return; - } - - // Parent folder is already being refreshed - if (_fileSystem.ContainsSubPath(refresher.Path, path)) - { - refresher.AddPath(path); - return; - } - - // New path is a parent - if (_fileSystem.ContainsSubPath(path, refresher.Path)) - { - refresher.ResetPath(path, null); - return; - } - - // They are siblings. Rebase the refresher to the parent folder. - if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) - { - refresher.ResetPath(parentPath, path); - return; - } - } - - var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger); - newRefresher.Completed += NewRefresher_Completed; - _activeRefreshers.Add(newRefresher); - } - } - - private void NewRefresher_Completed(object sender, EventArgs e) - { - var refresher = (FileRefresher)sender; - DisposeRefresher(refresher); - } - - /// - /// Stops this instance. - /// - public void Stop() - { - LibraryManager.ItemAdded -= LibraryManager_ItemAdded; - LibraryManager.ItemRemoved -= LibraryManager_ItemRemoved; - - foreach (var watcher in _fileSystemWatchers.Values.ToList()) - { - watcher.Created -= watcher_Changed; - watcher.Deleted -= watcher_Changed; - watcher.Renamed -= watcher_Changed; - watcher.Changed -= watcher_Changed; - - try - { - watcher.EnableRaisingEvents = false; - } - catch (InvalidOperationException) - { - // Seeing this under mono on linux sometimes - // Collection was modified; enumeration operation may not execute. - } - - watcher.Dispose(); - } - - _fileSystemWatchers.Clear(); - DisposeRefreshers(); - } - - private void DisposeRefresher(FileRefresher refresher) - { - lock (_activeRefreshers) - { - refresher.Dispose(); - _activeRefreshers.Remove(refresher); - } - } - - private void DisposeRefreshers() - { - lock (_activeRefreshers) - { - foreach (var refresher in _activeRefreshers.ToList()) - { - refresher.Dispose(); - } - _activeRefreshers.Clear(); - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - Stop(); - } - } - } - - public class LibraryMonitorStartup : IServerEntryPoint - { - private readonly ILibraryMonitor _monitor; - - public LibraryMonitorStartup(ILibraryMonitor monitor) - { - _monitor = monitor; - } - - public void Run() - { - _monitor.Start(); - } - - public void Dispose() - { - } - } -} diff --git a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs b/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs deleted file mode 100644 index b86a5f5d4..000000000 --- a/MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs +++ /dev/null @@ -1,384 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Security; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Localization; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Entities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using CommonIO; -using MoreLinq; - -namespace MediaBrowser.Server.Implementations.Intros -{ - public class DefaultIntroProvider : IIntroProvider - { - private readonly ISecurityManager _security; - private readonly ILocalizationManager _localization; - private readonly IConfigurationManager _serverConfig; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - private readonly IMediaSourceManager _mediaSourceManager; - - public DefaultIntroProvider(ISecurityManager security, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager) - { - _security = security; - _localization = localization; - _serverConfig = serverConfig; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - _mediaSourceManager = mediaSourceManager; - } - - public async Task> GetIntros(BaseItem item, User user) - { - var config = GetOptions(); - - if (item is Movie) - { - if (!config.EnableIntrosForMovies) - { - return new List(); - } - } - else if (item is Episode) - { - if (!config.EnableIntrosForEpisodes) - { - return new List(); - } - } - else - { - return new List(); - } - - var ratingLevel = string.IsNullOrWhiteSpace(item.OfficialRating) - ? null - : _localization.GetRatingLevel(item.OfficialRating); - - var candidates = new List(); - - var trailerTypes = new List(); - var sourceTypes = new List(); - - if (config.EnableIntrosFromMoviesInLibrary) - { - trailerTypes.Add(TrailerType.LocalTrailer); - sourceTypes.Add(SourceType.Library); - } - - if (IsSupporter) - { - if (config.EnableIntrosFromUpcomingTrailers) - { - trailerTypes.Add(TrailerType.ComingSoonToTheaters); - sourceTypes.Clear(); - } - if (config.EnableIntrosFromUpcomingDvdMovies) - { - trailerTypes.Add(TrailerType.ComingSoonToDvd); - sourceTypes.Clear(); - } - if (config.EnableIntrosFromUpcomingStreamingMovies) - { - trailerTypes.Add(TrailerType.ComingSoonToStreaming); - sourceTypes.Clear(); - } - if (config.EnableIntrosFromSimilarMovies) - { - trailerTypes.Add(TrailerType.Archive); - sourceTypes.Clear(); - } - } - - if (trailerTypes.Count > 0) - { - var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Trailer).Name }, - TrailerTypes = trailerTypes.ToArray(), - SimilarTo = item, - IsPlayed = config.EnableIntrosForWatchedContent ? (bool?)null : false, - MaxParentalRating = config.EnableIntrosParentalControl ? ratingLevel : null, - BlockUnratedItems = config.EnableIntrosParentalControl ? new[] { UnratedItem.Trailer } : new UnratedItem[] { }, - - // Account for duplicates by imdb id, since the database doesn't support this yet - Limit = config.TrailerLimit * 2, - SourceTypes = sourceTypes.ToArray() - - }).Where(i => string.IsNullOrWhiteSpace(i.GetProviderId(MetadataProviders.Imdb)) || !string.Equals(i.GetProviderId(MetadataProviders.Imdb), item.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).Take(config.TrailerLimit); - - candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer - { - Item = i, - Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer, - LibraryManager = _libraryManager - })); - } - - return GetResult(item, candidates, config); - } - - private IEnumerable GetResult(BaseItem item, IEnumerable candidates, CinemaModeConfiguration config) - { - var customIntros = !string.IsNullOrWhiteSpace(config.CustomIntroPath) ? - GetCustomIntros(config) : - new List(); - - var mediaInfoIntros = !string.IsNullOrWhiteSpace(config.MediaInfoIntroPath) ? - GetMediaInfoIntros(config, item) : - new List(); - - // Avoid implicitly captured closure - return candidates.Select(i => i.IntroInfo) - .Concat(customIntros.Take(1)) - .Concat(mediaInfoIntros); - } - - private CinemaModeConfiguration GetOptions() - { - return _serverConfig.GetConfiguration("cinemamode"); - } - - private List GetCustomIntros(CinemaModeConfiguration options) - { - try - { - return GetCustomIntroFiles(options, true, false) - .OrderBy(i => Guid.NewGuid()) - .Select(i => new IntroInfo - { - Path = i - - }).ToList(); - } - catch (IOException) - { - return new List(); - } - } - - private IEnumerable GetMediaInfoIntros(CinemaModeConfiguration options, BaseItem item) - { - try - { - var hasMediaSources = item as IHasMediaSources; - - if (hasMediaSources == null) - { - return new List(); - } - - var mediaSource = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false) - .FirstOrDefault(); - - if (mediaSource == null) - { - return new List(); - } - - var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); - - var allIntros = GetCustomIntroFiles(options, false, true) - .OrderBy(i => Guid.NewGuid()) - .Select(i => new IntroInfo - { - Path = i - - }).ToList(); - - var returnResult = new List(); - - if (videoStream != null) - { - returnResult.AddRange(GetMediaInfoIntrosByVideoStream(allIntros, videoStream).Take(1)); - } - - if (audioStream != null) - { - returnResult.AddRange(GetMediaInfoIntrosByAudioStream(allIntros, audioStream).Take(1)); - } - - returnResult.AddRange(GetMediaInfoIntrosByTags(allIntros, item.Tags).Take(1)); - - return returnResult.DistinctBy(i => i.Path, StringComparer.OrdinalIgnoreCase); - } - catch (IOException) - { - return new List(); - } - } - - private IEnumerable GetMediaInfoIntrosByVideoStream(List allIntros, MediaStream stream) - { - var codec = stream.Codec; - - if (string.IsNullOrWhiteSpace(codec)) - { - return new List(); - } - - return allIntros - .Where(i => IsMatch(i.Path, codec)) - .OrderBy(i => Guid.NewGuid()); - } - - private IEnumerable GetMediaInfoIntrosByAudioStream(List allIntros, MediaStream stream) - { - var codec = stream.Codec; - - if (string.IsNullOrWhiteSpace(codec)) - { - return new List(); - } - - return allIntros - .Where(i => IsAudioMatch(i.Path, stream)) - .OrderBy(i => Guid.NewGuid()); - } - - private IEnumerable GetMediaInfoIntrosByTags(List allIntros, List tags) - { - return allIntros - .Where(i => tags.Any(t => IsMatch(i.Path, t))) - .OrderBy(i => Guid.NewGuid()); - } - - private bool IsMatch(string file, string attribute) - { - var filename = Path.GetFileNameWithoutExtension(file) ?? string.Empty; - filename = Normalize(filename); - - if (string.IsNullOrWhiteSpace(filename)) - { - return false; - } - - attribute = Normalize(attribute); - if (string.IsNullOrWhiteSpace(attribute)) - { - return false; - } - - return string.Equals(filename, attribute, StringComparison.OrdinalIgnoreCase); - } - - private string Normalize(string value) - { - return value; - } - - private bool IsAudioMatch(string path, MediaStream stream) - { - if (!string.IsNullOrWhiteSpace(stream.Codec)) - { - if (IsMatch(path, stream.Codec)) - { - return true; - } - } - if (!string.IsNullOrWhiteSpace(stream.Profile)) - { - if (IsMatch(path, stream.Profile)) - { - return true; - } - } - - return false; - } - - private IEnumerable GetCustomIntroFiles(CinemaModeConfiguration options, bool enableCustomIntros, bool enableMediaInfoIntros) - { - var list = new List(); - - if (enableCustomIntros && !string.IsNullOrWhiteSpace(options.CustomIntroPath)) - { - list.AddRange(_fileSystem.GetFilePaths(options.CustomIntroPath, true) - .Where(_libraryManager.IsVideoFile)); - } - - if (enableMediaInfoIntros && !string.IsNullOrWhiteSpace(options.MediaInfoIntroPath)) - { - list.AddRange(_fileSystem.GetFilePaths(options.MediaInfoIntroPath, true) - .Where(_libraryManager.IsVideoFile)); - } - - return list.Distinct(StringComparer.OrdinalIgnoreCase); - } - - public IEnumerable GetAllIntroFiles() - { - return GetCustomIntroFiles(GetOptions(), true, true); - } - - private bool IsSupporter - { - get { return _security.IsMBSupporter; } - } - - public string Name - { - get { return "Default"; } - } - - internal class ItemWithTrailer - { - internal BaseItem Item; - internal ItemWithTrailerType Type; - internal ILibraryManager LibraryManager; - - public IntroInfo IntroInfo - { - get - { - var id = Item.Id; - - if (Type == ItemWithTrailerType.ItemWithTrailer) - { - var hasTrailers = Item as IHasTrailers; - - if (hasTrailers != null) - { - id = hasTrailers.LocalTrailerIds.FirstOrDefault(); - } - } - return new IntroInfo - { - ItemId = id - }; - } - } - } - - internal enum ItemWithTrailerType - { - ChannelTrailer, - ItemWithTrailer - } - } - - public class CinemaModeConfigurationFactory : IConfigurationFactory - { - public IEnumerable GetConfigurations() - { - return new[] - { - new ConfigurationStore - { - ConfigurationType = typeof(CinemaModeConfiguration), - Key = "cinemamode" - } - }; - } - } - -} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs deleted file mode 100644 index d5abcf98e..000000000 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ /dev/null @@ -1,1310 +0,0 @@ -using System.Net; -using MediaBrowser.Common; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.LiveTv; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.LiveTv.Listings -{ - public class SchedulesDirect : IListingsProvider - { - private readonly ILogger _logger; - private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; - private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); - private readonly IApplicationHost _appHost; - - private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; - - private readonly Dictionary> _channelPairingCache = - new Dictionary>(StringComparer.OrdinalIgnoreCase); - - public SchedulesDirect(ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IApplicationHost appHost) - { - _logger = logger; - _jsonSerializer = jsonSerializer; - _httpClient = httpClient; - _appHost = appHost; - } - - private string UserAgent - { - get { return "Emby/" + _appHost.ApplicationVersion; } - } - - private List GetScheduleRequestDates(DateTime startDateUtc, DateTime endDateUtc) - { - List dates = new List(); - - var start = new List { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date; - var end = new List { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date; - - while (start <= end) - { - dates.Add(start.ToString("yyyy-MM-dd")); - start = start.AddDays(1); - } - - return dates; - } - - public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) - { - List programsInfo = new List(); - - var token = await GetToken(info, cancellationToken).ConfigureAwait(false); - - if (string.IsNullOrWhiteSpace(token)) - { - _logger.Warn("SchedulesDirect token is empty, returning empty program list"); - return programsInfo; - } - - if (string.IsNullOrWhiteSpace(info.ListingsId)) - { - _logger.Warn("ListingsId is null, returning empty program list"); - return programsInfo; - } - - var dates = GetScheduleRequestDates(startDateUtc, endDateUtc); - - ScheduleDirect.Station station = GetStation(info.ListingsId, channelNumber, channelName); - - if (station == null) - { - _logger.Info("No Schedules Direct Station found for channel {0} with name {1}", channelNumber, channelName); - return programsInfo; - } - - string stationID = station.stationID; - - _logger.Info("Channel Station ID is: " + stationID); - List requestList = - new List() - { - new ScheduleDirect.RequestScheduleForChannel() - { - stationID = stationID, - date = dates - } - }; - - var requestString = _jsonSerializer.SerializeToString(requestList); - _logger.Debug("Request string for schedules is: " + requestString); - - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/schedules", - UserAgent = UserAgent, - CancellationToken = cancellationToken, - // The data can be large so give it some extra time - TimeoutMs = 60000, - LogErrorResponseBody = true - }; - - httpOptions.RequestHeaders["token"] = token; - - httpOptions.RequestContent = requestString; - using (var response = await Post(httpOptions, true, info).ConfigureAwait(false)) - { - StreamReader reader = new StreamReader(response.Content); - string responseString = reader.ReadToEnd(); - var dailySchedules = _jsonSerializer.DeserializeFromString>(responseString); - _logger.Debug("Found " + dailySchedules.Count + " programs on " + channelNumber + " ScheduleDirect"); - - httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/programs", - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true, - // The data can be large so give it some extra time - TimeoutMs = 60000 - }; - - httpOptions.RequestHeaders["token"] = token; - - List programsID = new List(); - programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList(); - var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]"; - httpOptions.RequestContent = requestBody; - - using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) - { - StreamReader innerReader = new StreamReader(innerResponse.Content); - responseString = innerReader.ReadToEnd(); - - var programDetails = - _jsonSerializer.DeserializeFromString>( - responseString); - var programDict = programDetails.ToDictionary(p => p.programID, y => y); - - var images = await GetImageForPrograms(info, programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken); - - var schedules = dailySchedules.SelectMany(d => d.programs); - foreach (ScheduleDirect.Program schedule in schedules) - { - //_logger.Debug("Proccesing Schedule for statio ID " + stationID + - // " which corresponds to channel " + channelNumber + " and program id " + - // schedule.programID + " which says it has images? " + - // programDict[schedule.programID].hasImageArtwork); - - if (images != null) - { - var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10)); - if (imageIndex > -1) - { - var programEntry = programDict[schedule.programID]; - - var data = images[imageIndex].data ?? new List(); - data = data.OrderByDescending(GetSizeOrder).ToList(); - - programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600); - //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false); - //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? - // GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? - // GetProgramImage(ApiUrl, data, "Banner-LO", false) ?? - // GetProgramImage(ApiUrl, data, "Banner-LOT", false); - } - } - - programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID])); - } - _logger.Info("Finished with EPGData"); - } - } - - return programsInfo; - } - - private int GetSizeOrder(ScheduleDirect.ImageData image) - { - if (!string.IsNullOrWhiteSpace(image.height)) - { - int value; - if (int.TryParse(image.height, out value)) - { - return value; - } - } - - return 0; - } - - private readonly object _channelCacheLock = new object(); - private ScheduleDirect.Station GetStation(string listingsId, string channelNumber, string channelName) - { - lock (_channelCacheLock) - { - Dictionary channelPair; - if (_channelPairingCache.TryGetValue(listingsId, out channelPair)) - { - ScheduleDirect.Station station; - - if (channelPair.TryGetValue(channelNumber, out station)) - { - return station; - } - - if (!string.IsNullOrWhiteSpace(channelName)) - { - channelName = NormalizeName(channelName); - - var result = channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase)); - - if (result != null) - { - return result; - } - } - - if (!string.IsNullOrWhiteSpace(channelNumber)) - { - return channelPair.Values.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase)); - } - } - - return null; - } - } - - private void AddToChannelPairCache(string listingsId, string channelNumber, ScheduleDirect.Station schChannel) - { - lock (_channelCacheLock) - { - Dictionary cache; - if (_channelPairingCache.TryGetValue(listingsId, out cache)) - { - cache[channelNumber] = schChannel; - } - else - { - cache = new Dictionary(); - cache[channelNumber] = schChannel; - _channelPairingCache[listingsId] = cache; - } - } - } - - private void ClearPairCache(string listingsId) - { - lock (_channelCacheLock) - { - Dictionary cache; - if (_channelPairingCache.TryGetValue(listingsId, out cache)) - { - cache.Clear(); - } - } - } - - private int GetChannelPairCacheCount(string listingsId) - { - lock (_channelCacheLock) - { - Dictionary cache; - if (_channelPairingCache.TryGetValue(listingsId, out cache)) - { - return cache.Count; - } - - return 0; - } - } - - private string NormalizeName(string value) - { - return value.Replace(" ", string.Empty).Replace("-", string.Empty); - } - - public async Task AddMetadata(ListingsProviderInfo info, List channels, - CancellationToken cancellationToken) - { - var listingsId = info.ListingsId; - if (string.IsNullOrWhiteSpace(listingsId)) - { - throw new Exception("ListingsId required"); - } - - var token = await GetToken(info, cancellationToken); - - if (string.IsNullOrWhiteSpace(token)) - { - throw new Exception("token required"); - } - - ClearPairCache(listingsId); - - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/lineups/" + listingsId, - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true, - // The data can be large so give it some extra time - TimeoutMs = 60000 - }; - - httpOptions.RequestHeaders["token"] = token; - - using (var response = await Get(httpOptions, true, info).ConfigureAwait(false)) - { - var root = _jsonSerializer.DeserializeFromStream(response); - _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect"); - _logger.Info("Mapping Stations to Channel"); - foreach (ScheduleDirect.Map map in root.map) - { - var channelNumber = map.logicalChannelNumber; - - if (string.IsNullOrWhiteSpace(channelNumber)) - { - channelNumber = map.channel; - } - if (string.IsNullOrWhiteSpace(channelNumber)) - { - channelNumber = map.atscMajor + "." + map.atscMinor; - } - channelNumber = channelNumber.TrimStart('0'); - - _logger.Debug("Found channel: " + channelNumber + " in Schedules Direct"); - - var schChannel = (root.stations ?? new List()).FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); - if (schChannel != null) - { - AddToChannelPairCache(listingsId, channelNumber, schChannel); - } - else - { - AddToChannelPairCache(listingsId, channelNumber, new ScheduleDirect.Station - { - stationID = map.stationID - }); - } - } - _logger.Info("Added " + GetChannelPairCacheCount(listingsId) + " channels to the dictionary"); - - foreach (ChannelInfo channel in channels) - { - var station = GetStation(listingsId, channel.Number, channel.Name); - - if (station != null) - { - if (station.logo != null) - { - channel.ImageUrl = station.logo.URL; - channel.HasImage = true; - } - - if (!string.IsNullOrWhiteSpace(station.name)) - { - channel.Name = station.name; - } - } - else - { - _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + channel.Name); - } - } - } - } - - private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, - ScheduleDirect.ProgramDetails details) - { - //_logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); - DateTime startAt = GetDate(programInfo.airDateTime); - DateTime endAt = startAt.AddSeconds(programInfo.duration); - ProgramAudio audioType = ProgramAudio.Stereo; - - bool repeat = programInfo.@new == null; - string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channel; - - if (programInfo.audioProperties != null) - { - if (programInfo.audioProperties.Exists(item => string.Equals(item, "atmos", StringComparison.OrdinalIgnoreCase))) - { - audioType = ProgramAudio.Atmos; - } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd 5.1", StringComparison.OrdinalIgnoreCase))) - { - audioType = ProgramAudio.DolbyDigital; - } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "dd", StringComparison.OrdinalIgnoreCase))) - { - audioType = ProgramAudio.DolbyDigital; - } - else if (programInfo.audioProperties.Exists(item => string.Equals(item, "stereo", StringComparison.OrdinalIgnoreCase))) - { - audioType = ProgramAudio.Stereo; - } - else - { - audioType = ProgramAudio.Mono; - } - } - - string episodeTitle = null; - if (details.episodeTitle150 != null) - { - episodeTitle = details.episodeTitle150; - } - - var showType = details.showType ?? string.Empty; - - var info = new ProgramInfo - { - ChannelId = channel, - Id = newID, - StartDate = startAt, - EndDate = endAt, - Name = details.titles[0].title120 ?? "Unkown", - OfficialRating = null, - CommunityRating = null, - EpisodeTitle = episodeTitle, - Audio = audioType, - IsRepeat = repeat, - IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, - ImageUrl = details.primaryImage, - IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), - IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, - IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, - ShowId = programInfo.programID, - Etag = programInfo.md5 - }; - - if (programInfo.videoProperties != null) - { - info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); - info.Is3D = programInfo.videoProperties.Contains("3d", StringComparer.OrdinalIgnoreCase); - } - - if (details.contentRating != null && details.contentRating.Count > 0) - { - info.OfficialRating = details.contentRating[0].code.Replace("TV", "TV-").Replace("--", "-"); - - var invalid = new[] { "N/A", "Approved", "Not Rated", "Passed" }; - if (invalid.Contains(info.OfficialRating, StringComparer.OrdinalIgnoreCase)) - { - info.OfficialRating = null; - } - } - - if (details.descriptions != null) - { - if (details.descriptions.description1000 != null) - { - info.Overview = details.descriptions.description1000[0].description; - } - else if (details.descriptions.description100 != null) - { - info.ShortOverview = details.descriptions.description100[0].description; - } - } - - if (info.IsSeries) - { - info.SeriesId = programInfo.programID.Substring(0, 10); - - if (details.metadata != null) - { - var gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; - info.SeasonNumber = gracenote.season; - info.EpisodeNumber = gracenote.episode; - } - } - - if (!string.IsNullOrWhiteSpace(details.originalAirDate) && (!info.IsSeries || info.IsRepeat)) - { - info.OriginalAirDate = DateTime.Parse(details.originalAirDate); - info.ProductionYear = info.OriginalAirDate.Value.Year; - } - - if (details.genres != null) - { - info.Genres = details.genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); - info.IsNews = details.genres.Contains("news", StringComparer.OrdinalIgnoreCase); - - if (info.Genres.Contains("children", StringComparer.OrdinalIgnoreCase)) - { - info.IsKids = true; - } - } - - return info; - } - - private DateTime GetDate(string value) - { - var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); - - if (date.Kind != DateTimeKind.Utc) - { - date = DateTime.SpecifyKind(date, DateTimeKind.Utc); - } - return date; - } - - private string GetProgramImage(string apiUrl, List images, string category, bool returnDefaultImage, int desiredWidth) - { - string url = null; - - var matches = images - .Where(i => string.Equals(i.category, category, StringComparison.OrdinalIgnoreCase)) - .ToList(); - - if (matches.Count == 0) - { - if (!returnDefaultImage) - { - return null; - } - matches = images; - } - - var match = matches.FirstOrDefault(i => - { - if (!string.IsNullOrWhiteSpace(i.width)) - { - int value; - if (int.TryParse(i.width, out value)) - { - return value <= desiredWidth; - } - } - - return false; - }); - - if (match == null) - { - // Get the second lowest quality image, when possible - if (matches.Count > 1) - { - match = matches[matches.Count - 2]; - } - else - { - match = matches.FirstOrDefault(); - } - } - - if (match == null) - { - return null; - } - - var uri = match.uri; - - if (!string.IsNullOrWhiteSpace(uri)) - { - if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1) - { - url = uri; - } - else - { - url = apiUrl + "/image/" + uri; - } - } - //_logger.Debug("URL for image is : " + url); - return url; - } - - private async Task> GetImageForPrograms( - ListingsProviderInfo info, - List programIds, - CancellationToken cancellationToken) - { - var imageIdString = "["; - - programIds.ForEach(i => - { - if (!imageIdString.Contains(i.Substring(0, 10))) - { - imageIdString += "\"" + i.Substring(0, 10) + "\","; - } - }); - imageIdString = imageIdString.TrimEnd(',') + "]"; - - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/metadata/programs", - UserAgent = UserAgent, - CancellationToken = cancellationToken, - RequestContent = imageIdString, - LogErrorResponseBody = true, - // The data can be large so give it some extra time - TimeoutMs = 60000 - }; - List images; - using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false)) - { - images = _jsonSerializer.DeserializeFromStream>( - innerResponse2.Content); - } - - return images; - } - - public async Task> GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken) - { - var token = await GetToken(info, cancellationToken); - - var lineups = new List(); - - if (string.IsNullOrWhiteSpace(token)) - { - return lineups; - } - - var options = new HttpRequestOptions() - { - Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location, - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true - }; - - options.RequestHeaders["token"] = token; - - try - { - using (Stream responce = await Get(options, false, info).ConfigureAwait(false)) - { - var root = _jsonSerializer.DeserializeFromStream>(responce); - - if (root != null) - { - foreach (ScheduleDirect.Headends headend in root) - { - foreach (ScheduleDirect.Lineup lineup in headend.lineups) - { - lineups.Add(new NameIdPair - { - Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, - Id = lineup.uri.Substring(18) - }); - } - } - } - else - { - _logger.Info("No lineups available"); - } - } - } - catch (Exception ex) - { - _logger.Error("Error getting headends", ex); - } - - return lineups; - } - - private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); - private DateTime _lastErrorResponse; - private async Task GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) - { - var username = info.Username; - - // Reset the token if there's no username - if (string.IsNullOrWhiteSpace(username)) - { - return null; - } - - var password = info.Password; - if (string.IsNullOrWhiteSpace(password)) - { - return null; - } - - // Avoid hammering SD - if ((DateTime.UtcNow - _lastErrorResponse).TotalMinutes < 1) - { - return null; - } - - NameValuePair savedToken = null; - if (!_tokens.TryGetValue(username, out savedToken)) - { - savedToken = new NameValuePair(); - _tokens.TryAdd(username, savedToken); - } - - if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) - { - long ticks; - if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) - { - // If it's under 24 hours old we can still use it - if (DateTime.UtcNow.Ticks - ticks < TimeSpan.FromHours(20).Ticks) - { - return savedToken.Name; - } - } - } - - await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); - savedToken.Name = result; - savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); - return result; - } - catch (HttpException ex) - { - if (ex.StatusCode.HasValue) - { - if ((int)ex.StatusCode.Value == 400) - { - _tokens.Clear(); - _lastErrorResponse = DateTime.UtcNow; - } - } - throw; - } - finally - { - _tokenSemaphore.Release(); - } - } - - private async Task Post(HttpRequestOptions options, - bool enableRetry, - ListingsProviderInfo providerInfo) - { - try - { - return await _httpClient.Post(options).ConfigureAwait(false); - } - catch (HttpException ex) - { - _tokens.Clear(); - - if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500) - { - enableRetry = false; - } - - if (!enableRetry) - { - throw; - } - } - - var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false); - options.RequestHeaders["token"] = newToken; - return await Post(options, false, providerInfo).ConfigureAwait(false); - } - - private async Task Get(HttpRequestOptions options, - bool enableRetry, - ListingsProviderInfo providerInfo) - { - try - { - return await _httpClient.Get(options).ConfigureAwait(false); - } - catch (HttpException ex) - { - _tokens.Clear(); - - if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500) - { - enableRetry = false; - } - - if (!enableRetry) - { - throw; - } - } - - var newToken = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false); - options.RequestHeaders["token"] = newToken; - return await Get(options, false, providerInfo).ConfigureAwait(false); - } - - private async Task GetTokenInternal(string username, string password, - CancellationToken cancellationToken) - { - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/token", - UserAgent = UserAgent, - RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", - CancellationToken = cancellationToken, - LogErrorResponseBody = true - }; - //_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + - // httpOptions.RequestContent); - - using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false)) - { - var root = _jsonSerializer.DeserializeFromStream(responce.Content); - if (root.message == "OK") - { - _logger.Info("Authenticated with Schedules Direct token: " + root.token); - return root.token; - } - - throw new ApplicationException("Could not authenticate with Schedules Direct Error: " + root.message); - } - } - - private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken) - { - var token = await GetToken(info, cancellationToken); - - if (string.IsNullOrWhiteSpace(token)) - { - throw new ArgumentException("Authentication required."); - } - - if (string.IsNullOrWhiteSpace(info.ListingsId)) - { - throw new ArgumentException("Listings Id required"); - } - - _logger.Info("Adding new LineUp "); - - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/lineups/" + info.ListingsId, - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true, - BufferContent = false - }; - - httpOptions.RequestHeaders["token"] = token; - - using (var response = await _httpClient.SendAsync(httpOptions, "PUT")) - { - } - } - - public string Name - { - get { return "Schedules Direct"; } - } - - public static string TypeName = "SchedulesDirect"; - public string Type - { - get { return TypeName; } - } - - private async Task HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) - { - if (string.IsNullOrWhiteSpace(info.ListingsId)) - { - throw new ArgumentException("Listings Id required"); - } - - var token = await GetToken(info, cancellationToken); - - if (string.IsNullOrWhiteSpace(token)) - { - throw new Exception("token required"); - } - - _logger.Info("Headends on account "); - - var options = new HttpRequestOptions() - { - Url = ApiUrl + "/lineups", - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true - }; - - options.RequestHeaders["token"] = token; - - try - { - using (var response = await Get(options, false, null).ConfigureAwait(false)) - { - var root = _jsonSerializer.DeserializeFromStream(response); - - return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); - } - } - catch (HttpException ex) - { - // Apparently we're supposed to swallow this - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) - { - return false; - } - - throw; - } - } - - public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) - { - if (validateLogin) - { - if (string.IsNullOrWhiteSpace(info.Username)) - { - throw new ArgumentException("Username is required"); - } - if (string.IsNullOrWhiteSpace(info.Password)) - { - throw new ArgumentException("Password is required"); - } - } - if (validateListings) - { - if (string.IsNullOrWhiteSpace(info.ListingsId)) - { - throw new ArgumentException("Listings Id required"); - } - - var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false); - - if (!hasLineup) - { - await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); - } - } - } - - public Task> GetLineups(ListingsProviderInfo info, string country, string location) - { - return GetHeadends(info, country, location, CancellationToken.None); - } - - public async Task> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) - { - var listingsId = info.ListingsId; - if (string.IsNullOrWhiteSpace(listingsId)) - { - throw new Exception("ListingsId required"); - } - - await AddMetadata(info, new List(), cancellationToken).ConfigureAwait(false); - - var token = await GetToken(info, cancellationToken); - - if (string.IsNullOrWhiteSpace(token)) - { - throw new Exception("token required"); - } - - var httpOptions = new HttpRequestOptions() - { - Url = ApiUrl + "/lineups/" + listingsId, - UserAgent = UserAgent, - CancellationToken = cancellationToken, - LogErrorResponseBody = true, - // The data can be large so give it some extra time - TimeoutMs = 60000 - }; - - httpOptions.RequestHeaders["token"] = token; - - var list = new List(); - - using (var response = await Get(httpOptions, true, info).ConfigureAwait(false)) - { - var root = _jsonSerializer.DeserializeFromStream(response); - _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect"); - _logger.Info("Mapping Stations to Channel"); - foreach (ScheduleDirect.Map map in root.map) - { - var channelNumber = map.logicalChannelNumber; - - if (string.IsNullOrWhiteSpace(channelNumber)) - { - channelNumber = map.channel; - } - if (string.IsNullOrWhiteSpace(channelNumber)) - { - channelNumber = map.atscMajor + "." + map.atscMinor; - } - channelNumber = channelNumber.TrimStart('0'); - - var name = channelNumber; - var station = GetStation(listingsId, channelNumber, null); - - if (station != null && !string.IsNullOrWhiteSpace(station.name)) - { - name = station.name; - } - - list.Add(new ChannelInfo - { - Number = channelNumber, - Name = name - }); - } - } - - return list; - } - - public class ScheduleDirect - { - public class Token - { - public int code { get; set; } - public string message { get; set; } - public string serverID { get; set; } - public string token { get; set; } - } - public class Lineup - { - public string lineup { get; set; } - public string name { get; set; } - public string transport { get; set; } - public string location { get; set; } - public string uri { get; set; } - } - - public class Lineups - { - public int code { get; set; } - public string serverID { get; set; } - public string datetime { get; set; } - public List lineups { get; set; } - } - - - public class Headends - { - public string headend { get; set; } - public string transport { get; set; } - public string location { get; set; } - public List lineups { get; set; } - } - - - - public class Map - { - public string stationID { get; set; } - public string channel { get; set; } - public string logicalChannelNumber { get; set; } - public int uhfVhf { get; set; } - public int atscMajor { get; set; } - public int atscMinor { get; set; } - } - - public class Broadcaster - { - public string city { get; set; } - public string state { get; set; } - public string postalcode { get; set; } - public string country { get; set; } - } - - public class Logo - { - public string URL { get; set; } - public int height { get; set; } - public int width { get; set; } - public string md5 { get; set; } - } - - public class Station - { - public string stationID { get; set; } - public string name { get; set; } - public string callsign { get; set; } - public List broadcastLanguage { get; set; } - public List descriptionLanguage { get; set; } - public Broadcaster broadcaster { get; set; } - public string affiliate { get; set; } - public Logo logo { get; set; } - public bool? isCommercialFree { get; set; } - } - - public class Metadata - { - public string lineup { get; set; } - public string modified { get; set; } - public string transport { get; set; } - } - - public class Channel - { - public List map { get; set; } - public List stations { get; set; } - public Metadata metadata { get; set; } - } - - public class RequestScheduleForChannel - { - public string stationID { get; set; } - public List date { get; set; } - } - - - - - public class Rating - { - public string body { get; set; } - public string code { get; set; } - } - - public class Multipart - { - public int partNumber { get; set; } - public int totalParts { get; set; } - } - - public class Program - { - public string programID { get; set; } - public string airDateTime { get; set; } - public int duration { get; set; } - public string md5 { get; set; } - public List audioProperties { get; set; } - public List videoProperties { get; set; } - public List ratings { get; set; } - public bool? @new { get; set; } - public Multipart multipart { get; set; } - } - - - - public class MetadataSchedule - { - public string modified { get; set; } - public string md5 { get; set; } - public string startDate { get; set; } - public string endDate { get; set; } - public int days { get; set; } - } - - public class Day - { - public string stationID { get; set; } - public List programs { get; set; } - public MetadataSchedule metadata { get; set; } - - public Day() - { - programs = new List(); - } - } - - // - public class Title - { - public string title120 { get; set; } - } - - public class EventDetails - { - public string subType { get; set; } - } - - public class Description100 - { - public string descriptionLanguage { get; set; } - public string description { get; set; } - } - - public class Description1000 - { - public string descriptionLanguage { get; set; } - public string description { get; set; } - } - - public class DescriptionsProgram - { - public List description100 { get; set; } - public List description1000 { get; set; } - } - - public class Gracenote - { - public int season { get; set; } - public int episode { get; set; } - } - - public class MetadataPrograms - { - public Gracenote Gracenote { get; set; } - } - - public class ContentRating - { - public string body { get; set; } - public string code { get; set; } - } - - public class Cast - { - public string billingOrder { get; set; } - public string role { get; set; } - public string nameId { get; set; } - public string personId { get; set; } - public string name { get; set; } - public string characterName { get; set; } - } - - public class Crew - { - public string billingOrder { get; set; } - public string role { get; set; } - public string nameId { get; set; } - public string personId { get; set; } - public string name { get; set; } - } - - public class QualityRating - { - public string ratingsBody { get; set; } - public string rating { get; set; } - public string minRating { get; set; } - public string maxRating { get; set; } - public string increment { get; set; } - } - - public class Movie - { - public string year { get; set; } - public int duration { get; set; } - public List qualityRating { get; set; } - } - - public class Recommendation - { - public string programID { get; set; } - public string title120 { get; set; } - } - - public class ProgramDetails - { - public string audience { get; set; } - public string programID { get; set; } - public List titles { get; set; } - public EventDetails eventDetails { get; set; } - public DescriptionsProgram descriptions { get; set; } - public string originalAirDate { get; set; } - public List<string> genres { get; set; } - public string episodeTitle150 { get; set; } - public List<MetadataPrograms> metadata { get; set; } - public List<ContentRating> contentRating { get; set; } - public List<Cast> cast { get; set; } - public List<Crew> crew { get; set; } - public string showType { get; set; } - public bool hasImageArtwork { get; set; } - public string primaryImage { get; set; } - public string thumbImage { get; set; } - public string bannerImage { get; set; } - public string imageID { get; set; } - public string md5 { get; set; } - public List<string> contentAdvisory { get; set; } - public Movie movie { get; set; } - public List<Recommendation> recommendations { get; set; } - } - - public class Caption - { - public string content { get; set; } - public string lang { get; set; } - } - - public class ImageData - { - public string width { get; set; } - public string height { get; set; } - public string uri { get; set; } - public string size { get; set; } - public string aspect { get; set; } - public string category { get; set; } - public string text { get; set; } - public string primary { get; set; } - public string tier { get; set; } - public Caption caption { get; set; } - } - - public class ShowImages - { - public string programID { get; set; } - public List<ImageData> data { get; set; } - } - - } - } -} \ No newline at end of file diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs deleted file mode 100644 index 6e188fae8..000000000 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ /dev/null @@ -1,1619 +0,0 @@ -using Emby.Drawing; -using Emby.Drawing.GDI; -using Emby.Drawing.ImageMagick; -using MediaBrowser.Api; -using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Implementations; -using MediaBrowser.Common.Implementations.ScheduledTasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Progress; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Activity; -using MediaBrowser.Controller.Channels; -using MediaBrowser.Controller.Chapters; -using MediaBrowser.Controller.Collections; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Devices; -using MediaBrowser.Controller.Dlna; -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.FileOrganization; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Localization; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.News; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Playlists; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Resolvers; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using MediaBrowser.Controller.Social; -using MediaBrowser.Controller.Sorting; -using MediaBrowser.Controller.Subtitles; -using MediaBrowser.Controller.Sync; -using MediaBrowser.Controller.TV; -using MediaBrowser.Dlna; -using MediaBrowser.Dlna.ConnectionManager; -using MediaBrowser.Dlna.ContentDirectory; -using MediaBrowser.Dlna.Main; -using MediaBrowser.Dlna.MediaReceiverRegistrar; -using MediaBrowser.Dlna.Ssdp; -using MediaBrowser.LocalMetadata.Savers; -using MediaBrowser.MediaEncoding.BdInfo; -using MediaBrowser.MediaEncoding.Encoder; -using MediaBrowser.MediaEncoding.Subtitles; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Updates; -using MediaBrowser.Providers.Chapters; -using MediaBrowser.Providers.Manager; -using MediaBrowser.Providers.Subtitles; -using MediaBrowser.Server.Implementations; -using MediaBrowser.Server.Implementations.Activity; -using MediaBrowser.Server.Implementations.Channels; -using MediaBrowser.Server.Implementations.Collections; -using MediaBrowser.Server.Implementations.Configuration; -using MediaBrowser.Server.Implementations.Connect; -using MediaBrowser.Server.Implementations.Devices; -using MediaBrowser.Server.Implementations.Dto; -using MediaBrowser.Server.Implementations.EntryPoints; -using MediaBrowser.Server.Implementations.FileOrganization; -using MediaBrowser.Server.Implementations.HttpServer; -using MediaBrowser.Server.Implementations.HttpServer.Security; -using MediaBrowser.Server.Implementations.IO; -using MediaBrowser.Server.Implementations.Library; -using MediaBrowser.Server.Implementations.LiveTv; -using MediaBrowser.Server.Implementations.Localization; -using MediaBrowser.Server.Implementations.MediaEncoder; -using MediaBrowser.Server.Implementations.Notifications; -using MediaBrowser.Server.Implementations.Persistence; -using MediaBrowser.Server.Implementations.Playlists; -using MediaBrowser.Server.Implementations.Security; -using MediaBrowser.Server.Implementations.ServerManager; -using MediaBrowser.Server.Implementations.Session; -using MediaBrowser.Server.Implementations.Social; -using MediaBrowser.Server.Implementations.Sync; -using MediaBrowser.Server.Implementations.TV; -using MediaBrowser.Server.Startup.Common.FFMpeg; -using MediaBrowser.Server.Startup.Common.Migrations; -using MediaBrowser.WebDashboard.Api; -using MediaBrowser.XbmcMetadata.Providers; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using CommonIO; -using MediaBrowser.Api.Playback; -using MediaBrowser.Common.Implementations.Serialization; -using MediaBrowser.Common.Implementations.Updates; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Server.Startup.Common -{ - /// <summary> - /// Class CompositionRoot - /// </summary> - public class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost - { - /// <summary> - /// Gets the server configuration manager. - /// </summary> - /// <value>The server configuration manager.</value> - public IServerConfigurationManager ServerConfigurationManager - { - get { return (IServerConfigurationManager)ConfigurationManager; } - } - - /// <summary> - /// Gets the configuration manager. - /// </summary> - /// <returns>IConfigurationManager.</returns> - protected override IConfigurationManager GetConfigurationManager() - { - return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager); - } - - /// <summary> - /// Gets or sets the server manager. - /// </summary> - /// <value>The server manager.</value> - private IServerManager ServerManager { get; set; } - /// <summary> - /// Gets or sets the user manager. - /// </summary> - /// <value>The user manager.</value> - public IUserManager UserManager { get; set; } - /// <summary> - /// Gets or sets the library manager. - /// </summary> - /// <value>The library manager.</value> - internal ILibraryManager LibraryManager { get; set; } - /// <summary> - /// Gets or sets the directory watchers. - /// </summary> - /// <value>The directory watchers.</value> - private ILibraryMonitor LibraryMonitor { get; set; } - /// <summary> - /// Gets or sets the provider manager. - /// </summary> - /// <value>The provider manager.</value> - private IProviderManager ProviderManager { get; set; } - /// <summary> - /// Gets or sets the HTTP server. - /// </summary> - /// <value>The HTTP server.</value> - private IHttpServer HttpServer { get; set; } - private IDtoService DtoService { get; set; } - private IImageProcessor ImageProcessor { get; set; } - - /// <summary> - /// Gets or sets the media encoder. - /// </summary> - /// <value>The media encoder.</value> - private IMediaEncoder MediaEncoder { get; set; } - private ISubtitleEncoder SubtitleEncoder { get; set; } - - private IConnectManager ConnectManager { get; set; } - private ISessionManager SessionManager { get; set; } - - private ILiveTvManager LiveTvManager { get; set; } - - public ILocalizationManager LocalizationManager { get; set; } - - private IEncodingManager EncodingManager { get; set; } - private IChannelManager ChannelManager { get; set; } - private ISyncManager SyncManager { get; set; } - - /// <summary> - /// Gets or sets the user data repository. - /// </summary> - /// <value>The user data repository.</value> - private IUserDataManager UserDataManager { get; set; } - private IUserRepository UserRepository { get; set; } - internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; } - internal IItemRepository ItemRepository { get; set; } - private INotificationsRepository NotificationsRepository { get; set; } - private IFileOrganizationRepository FileOrganizationRepository { get; set; } - - private INotificationManager NotificationManager { get; set; } - private ISubtitleManager SubtitleManager { get; set; } - private IChapterManager ChapterManager { get; set; } - private IDeviceManager DeviceManager { get; set; } - - internal IUserViewManager UserViewManager { get; set; } - - private IAuthenticationRepository AuthenticationRepository { get; set; } - private ISyncRepository SyncRepository { get; set; } - private ITVSeriesManager TVSeriesManager { get; set; } - private ICollectionManager CollectionManager { get; set; } - private IMediaSourceManager MediaSourceManager { get; set; } - private IPlaylistManager PlaylistManager { get; set; } - - private readonly StartupOptions _startupOptions; - private readonly string _releaseAssetFilename; - - internal INativeApp NativeApp { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="ApplicationHost" /> class. - /// </summary> - /// <param name="applicationPaths">The application paths.</param> - /// <param name="logManager">The log manager.</param> - /// <param name="options">The options.</param> - /// <param name="fileSystem">The file system.</param> - /// <param name="releaseAssetFilename">The release asset filename.</param> - /// <param name="nativeApp">The native application.</param> - public ApplicationHost(ServerApplicationPaths applicationPaths, - ILogManager logManager, - StartupOptions options, - IFileSystem fileSystem, - string releaseAssetFilename, - INativeApp nativeApp) - : base(applicationPaths, logManager, fileSystem) - { - _startupOptions = options; - _releaseAssetFilename = releaseAssetFilename; - NativeApp = nativeApp; - - SetBaseExceptionMessage(); - } - - private Version _version; - /// <summary> - /// Gets the current application version - /// </summary> - /// <value>The application version.</value> - public override Version ApplicationVersion - { - get - { - return _version ?? (_version = NativeApp.GetType().Assembly.GetName().Version); - } - } - - public override string OperatingSystemDisplayName - { - get { return NativeApp.Environment.OperatingSystemVersionString; } - } - - public override bool IsRunningAsService - { - get { return NativeApp.IsRunningAsService; } - } - - public bool SupportsRunningAsService - { - get { return NativeApp.SupportsRunningAsService; } - } - - public bool SupportsLibraryMonitor - { - get { return NativeApp.SupportsLibraryMonitor; } - } - - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - public override string Name - { - get - { - return "Emby Server"; - } - } - - /// <summary> - /// Gets a value indicating whether this instance can self restart. - /// </summary> - /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value> - public override bool CanSelfRestart - { - get { return NativeApp.CanSelfRestart; } - } - - public bool SupportsAutoRunAtStartup - { - get { return NativeApp.SupportsAutoRunAtStartup; } - } - - private void SetBaseExceptionMessage() - { - var builder = GetBaseExceptionMessage(ApplicationPaths); - - // Skip if plugins haven't been loaded yet - //if (Plugins != null) - //{ - // var pluginString = string.Join("|", Plugins.Select(i => i.Name + "-" + i.Version.ToString()).ToArray()); - // builder.Insert(0, string.Format("Plugins: {0}{1}", pluginString, Environment.NewLine)); - //} - - builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine)); - builder.Insert(0, "*** Error Report ***" + Environment.NewLine); - - LogManager.ExceptionMessagePrefix = builder.ToString(); - } - - /// <summary> - /// Runs the startup tasks. - /// </summary> - /// <summary> - /// Runs the startup tasks. - /// </summary> - public override async Task RunStartupTasks() - { - await PerformPreInitMigrations().ConfigureAwait(false); - - if (ServerConfigurationManager.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion && - ServerConfigurationManager.Configuration.IsStartupWizardCompleted) - { - TaskManager.SuspendTriggers = true; - } - - await base.RunStartupTasks().ConfigureAwait(false); - - await MediaEncoder.Init().ConfigureAwait(false); - - if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath)) - { - if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted) - { - ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false; - ServerConfigurationManager.SaveConfiguration(); - } - } - - Logger.Info("ServerId: {0}", SystemId); - Logger.Info("Core startup complete"); - HttpServer.GlobalResponse = null; - - PerformPostInitMigrations(); - Logger.Info("Post-init migrations complete"); - - foreach (var entryPoint in GetExports<IServerEntryPoint>().ToList()) - { - var name = entryPoint.GetType().FullName; - Logger.Info("Starting entry point {0}", name); - var now = DateTime.UtcNow; - try - { - entryPoint.Run(); - } - catch (Exception ex) - { - Logger.ErrorException("Error in {0}", ex, name); - } - Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); - } - Logger.Info("All entry points have started"); - - LogManager.RemoveConsoleOutput(); - } - - protected override IJsonSerializer CreateJsonSerializer() - { - var result = base.CreateJsonSerializer(); - - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ShortOverview" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "Taglines" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "Keywords" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ShortOverview" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ShortOverview" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth" }; - - ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds" }; - ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds" }; - - ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ImageInfos" }; - ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ImageInfos" }; - - ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProductionLocations" }; - ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProductionLocations" }; - - ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ThemeSongIds" }; - - ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ThemeVideoIds" }; - - return result; - } - - public override Task Init(IProgress<double> progress) - { - HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; - HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber; - - return base.Init(progress); - } - - private async Task PerformPreInitMigrations() - { - var migrations = new List<IVersionMigration> - { - new UpdateLevelMigration(ServerConfigurationManager, this, HttpClient, JsonSerializer, _releaseAssetFilename, Logger) - }; - - foreach (var task in migrations) - { - try - { - await task.Run().ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error running migration", ex); - } - } - } - - private void PerformPostInitMigrations() - { - var migrations = new List<IVersionMigration> - { - new MovieDbEpisodeProviderMigration(ServerConfigurationManager), - new DbMigration(ServerConfigurationManager, TaskManager) - }; - - foreach (var task in migrations) - { - try - { - task.Run(); - } - catch (Exception ex) - { - Logger.ErrorException("Error running migration", ex); - } - } - } - - /// <summary> - /// Registers resources that classes will depend on - /// </summary> - protected override async Task RegisterResources(IProgress<double> progress) - { - await base.RegisterResources(progress).ConfigureAwait(false); - - RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer)); - - RegisterSingleInstance<IServerApplicationHost>(this); - RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths); - - RegisterSingleInstance(ServerConfigurationManager); - - LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LogManager.GetLogger("LocalizationManager")); - RegisterSingleInstance(LocalizationManager); - - RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer()); - - UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager); - RegisterSingleInstance(UserDataManager); - - UserRepository = await GetUserRepository().ConfigureAwait(false); - - var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths, NativeApp.GetDbConnector(), MemoryStreamProvider); - DisplayPreferencesRepository = displayPreferencesRepo; - RegisterSingleInstance(DisplayPreferencesRepository); - - var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager, NativeApp.GetDbConnector(), MemoryStreamProvider); - ItemRepository = itemRepo; - RegisterSingleInstance(ItemRepository); - - FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false); - RegisterSingleInstance(FileOrganizationRepository); - - AuthenticationRepository = await GetAuthenticationRepository().ConfigureAwait(false); - RegisterSingleInstance(AuthenticationRepository); - - SyncRepository = await GetSyncRepository().ConfigureAwait(false); - RegisterSingleInstance(SyncRepository); - - UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager); - RegisterSingleInstance(UserManager); - - LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager); - RegisterSingleInstance(LibraryManager); - - var musicManager = new MusicManager(LibraryManager); - RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager)); - - LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, this); - RegisterSingleInstance(LibraryMonitor); - - ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer, MemoryStreamProvider); - RegisterSingleInstance(ProviderManager); - - RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager)); - - HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamProvider, "Emby", "web/index.html"); - HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); - RegisterSingleInstance(HttpServer, false); - progress.Report(10); - - ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamProvider); - RegisterSingleInstance(ServerManager); - - var innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15)); - - ImageProcessor = GetImageProcessor(); - RegisterSingleInstance(ImageProcessor); - - TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager); - RegisterSingleInstance(TVSeriesManager); - - SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer, TaskManager, MemoryStreamProvider); - RegisterSingleInstance(SyncManager); - - DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager); - RegisterSingleInstance(DtoService); - - var encryptionManager = new EncryptionManager(); - RegisterSingleInstance<IEncryptionManager>(encryptionManager); - - ConnectManager = new ConnectManager(LogManager.GetLogger("ConnectManager"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager); - RegisterSingleInstance(ConnectManager); - - DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager); - RegisterSingleInstance(DeviceManager); - - var newsService = new Implementations.News.NewsService(ApplicationPaths, JsonSerializer); - RegisterSingleInstance<INewsService>(newsService); - - var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager); - RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService); - - progress.Report(15); - - ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager); - RegisterSingleInstance(ChannelManager); - - MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager, UserDataManager); - RegisterSingleInstance(MediaSourceManager); - - SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager); - RegisterSingleInstance(SessionManager); - - var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this); - RegisterSingleInstance<IDlnaManager>(dlnaManager); - - var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient); - RegisterSingleInstance<IConnectionManager>(connectionManager); - - CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager); - RegisterSingleInstance(CollectionManager); - - PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager); - RegisterSingleInstance<IPlaylistManager>(PlaylistManager); - - LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, SecurityManager); - RegisterSingleInstance(LiveTvManager); - - UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager); - RegisterSingleInstance(UserViewManager); - - var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder); - RegisterSingleInstance<IContentDirectory>(contentDirectory); - - var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager); - RegisterSingleInstance<IMediaReceiverRegistrar>(mediaRegistrar); - - NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager); - RegisterSingleInstance(NotificationManager); - - SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager); - RegisterSingleInstance(SubtitleManager); - - RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager)); - - ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository); - RegisterSingleInstance(ChapterManager); - - await RegisterMediaEncoder(innerProgress).ConfigureAwait(false); - progress.Report(90); - - EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager); - RegisterSingleInstance(EncodingManager); - - var sharingRepo = new SharingRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector()); - await sharingRepo.Initialize().ConfigureAwait(false); - RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this)); - - var activityLogRepo = await GetActivityLogRepository().ConfigureAwait(false); - RegisterSingleInstance(activityLogRepo); - RegisterSingleInstance<IActivityManager>(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager)); - - var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager); - RegisterSingleInstance<IAuthorizationContext>(authContext); - RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager)); - RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager)); - - SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamProvider); - RegisterSingleInstance(SubtitleEncoder); - - await displayPreferencesRepo.Initialize().ConfigureAwait(false); - - var userDataRepo = new SqliteUserDataRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector()); - - ((UserDataManager)UserDataManager).Repository = userDataRepo; - await itemRepo.Initialize(userDataRepo).ConfigureAwait(false); - ((LibraryManager)LibraryManager).ItemRepository = ItemRepository; - await ConfigureNotificationsRepository().ConfigureAwait(false); - progress.Report(100); - - SetStaticProperties(); - - await ((UserManager)UserManager).Initialize().ConfigureAwait(false); - } - - private IImageProcessor GetImageProcessor() - { - var maxConcurrentImageProcesses = Math.Max(Environment.ProcessorCount, 4); - - if (_startupOptions.ContainsOption("-imagethreads")) - { - int.TryParse(_startupOptions.GetOption("-imagethreads"), NumberStyles.Any, CultureInfo.InvariantCulture, out maxConcurrentImageProcesses); - } - - return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, GetImageEncoder(), maxConcurrentImageProcesses, () => LibraryManager); - } - - private IImageEncoder GetImageEncoder() - { - if (!_startupOptions.ContainsOption("-enablegdi")) - { - try - { - return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager, ServerConfigurationManager); - } - catch - { - Logger.Error("Error loading ImageMagick. Will revert to GDI."); - } - } - - try - { - return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI")); - } - catch - { - Logger.Error("Error loading GDI. Will revert to NullImageEncoder."); - } - - return new NullImageEncoder(); - } - - protected override INetworkManager CreateNetworkManager(ILogger logger) - { - return NativeApp.CreateNetworkManager(logger); - } - - /// <summary> - /// Registers the media encoder. - /// </summary> - /// <returns>Task.</returns> - private async Task RegisterMediaEncoder(IProgress<double> progress) - { - string encoderPath = null; - string probePath = null; - - var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetFfmpegInstallInfo()) - .GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false); - - encoderPath = info.EncoderPath; - probePath = info.ProbePath; - var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase); - - var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), - JsonSerializer, - encoderPath, - probePath, - hasExternalEncoder, - ServerConfigurationManager, - FileSystemManager, - LiveTvManager, - IsoManager, - LibraryManager, - ChannelManager, - SessionManager, - () => SubtitleEncoder, - () => MediaSourceManager, - HttpClient, - ZipClient, MemoryStreamProvider); - - MediaEncoder = mediaEncoder; - RegisterSingleInstance(MediaEncoder); - } - - /// <summary> - /// Gets the user repository. - /// </summary> - /// <returns>Task{IUserRepository}.</returns> - private async Task<IUserRepository> GetUserRepository() - { - var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer, NativeApp.GetDbConnector(), MemoryStreamProvider); - - await repo.Initialize().ConfigureAwait(false); - - return repo; - } - - /// <summary> - /// Gets the file organization repository. - /// </summary> - /// <returns>Task{IUserRepository}.</returns> - private async Task<IFileOrganizationRepository> GetFileOrganizationRepository() - { - var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector()); - - await repo.Initialize().ConfigureAwait(false); - - return repo; - } - - private async Task<IAuthenticationRepository> GetAuthenticationRepository() - { - var repo = new AuthenticationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector()); - - await repo.Initialize().ConfigureAwait(false); - - return repo; - } - - private async Task<IActivityRepository> GetActivityLogRepository() - { - var repo = new ActivityRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector()); - - await repo.Initialize().ConfigureAwait(false); - - return repo; - } - - private async Task<ISyncRepository> GetSyncRepository() - { - var repo = new SyncRepository(LogManager, JsonSerializer, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector()); - - await repo.Initialize().ConfigureAwait(false); - - return repo; - } - - /// <summary> - /// Configures the repositories. - /// </summary> - private async Task ConfigureNotificationsRepository() - { - var repo = new SqliteNotificationsRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector()); - - await repo.Initialize().ConfigureAwait(false); - - NotificationsRepository = repo; - - RegisterSingleInstance(NotificationsRepository); - } - - /// <summary> - /// Dirty hacks - /// </summary> - private void SetStaticProperties() - { - // For now there's no real way to inject these properly - BaseItem.Logger = LogManager.GetLogger("BaseItem"); - BaseItem.ConfigurationManager = ServerConfigurationManager; - BaseItem.LibraryManager = LibraryManager; - BaseItem.ProviderManager = ProviderManager; - BaseItem.LocalizationManager = LocalizationManager; - BaseItem.ItemRepository = ItemRepository; - User.XmlSerializer = XmlSerializer; - User.UserManager = UserManager; - Folder.UserManager = UserManager; - BaseItem.FileSystem = FileSystemManager; - BaseItem.UserDataManager = UserDataManager; - BaseItem.ChannelManager = ChannelManager; - BaseItem.LiveTvManager = LiveTvManager; - Folder.UserViewManager = UserViewManager; - UserView.TVSeriesManager = TVSeriesManager; - UserView.PlaylistManager = PlaylistManager; - BaseItem.CollectionManager = CollectionManager; - BaseItem.MediaSourceManager = MediaSourceManager; - CollectionFolder.XmlSerializer = XmlSerializer; - BaseStreamingService.AppHost = this; - BaseStreamingService.HttpClient = HttpClient; - } - - /// <summary> - /// Finds the parts. - /// </summary> - protected override void FindParts() - { - if (!ServerConfigurationManager.Configuration.IsPortAuthorized) - { - RegisterServerWithAdministratorAccess(); - ServerConfigurationManager.Configuration.IsPortAuthorized = true; - ConfigurationManager.SaveConfiguration(); - } - - base.FindParts(); - - HttpServer.Init(GetExports<IRestfulService>(false)); - - ServerManager.AddWebSocketListeners(GetExports<IWebSocketListener>(false)); - - StartServer(); - - LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(), - GetExports<IVirtualFolderCreator>(), - GetExports<IItemResolver>(), - GetExports<IIntroProvider>(), - GetExports<IBaseItemComparer>(), - GetExports<ILibraryPostScanTask>()); - - ProviderManager.AddParts(GetExports<IImageProvider>(), - GetExports<IMetadataService>(), - GetExports<IMetadataProvider>(), - GetExports<IMetadataSaver>(), - GetExports<IExternalId>()); - - ImageProcessor.AddParts(GetExports<IImageEnhancer>()); - - LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>()); - - SubtitleManager.AddParts(GetExports<ISubtitleProvider>()); - - SessionManager.AddParts(GetExports<ISessionControllerFactory>()); - - ChannelManager.AddParts(GetExports<IChannel>()); - - MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>()); - - NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>()); - SyncManager.AddParts(GetExports<ISyncProvider>()); - } - - private string CertificatePath { get; set; } - - private IEnumerable<string> GetUrlPrefixes() - { - var hosts = new List<string>(); - - hosts.Add("+"); - - return hosts.SelectMany(i => - { - var prefixes = new List<string> - { - "http://"+i+":" + HttpPort + "/" - }; - - if (!string.IsNullOrWhiteSpace(CertificatePath)) - { - prefixes.Add("https://" + i + ":" + HttpsPort + "/"); - } - - return prefixes; - }); - } - - /// <summary> - /// Starts the server. - /// </summary> - private void StartServer() - { - CertificatePath = GetCertificatePath(true); - - try - { - ServerManager.Start(GetUrlPrefixes(), CertificatePath); - return; - } - catch (Exception ex) - { - Logger.ErrorException("Error starting http server", ex); - - if (HttpPort == 8096) - { - throw; - } - } - - HttpPort = 8096; - - try - { - ServerManager.Start(GetUrlPrefixes(), CertificatePath); - } - catch (Exception ex) - { - Logger.ErrorException("Error starting http server", ex); - - throw; - } - } - - private string GetCertificatePath(bool generateCertificate) - { - if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath)) - { - // Custom cert - return ServerConfigurationManager.Configuration.CertificatePath; - } - - // Generate self-signed cert - var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns); - var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + certHost.GetMD5().ToString("N") + ".pfx"); - - if (generateCertificate) - { - if (!FileSystemManager.FileExists(certPath)) - { - FileSystemManager.CreateDirectory(Path.GetDirectoryName(certPath)); - - try - { - NetworkManager.GenerateSelfSignedSslCertificate(certPath, certHost); - } - catch (Exception ex) - { - Logger.ErrorException("Error creating ssl cert", ex); - return null; - } - } - } - - return certPath; - } - - /// <summary> - /// Called when [configuration updated]. - /// </summary> - /// <param name="sender">The sender.</param> - /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> - protected override void OnConfigurationUpdated(object sender, EventArgs e) - { - base.OnConfigurationUpdated(sender, e); - - var requiresRestart = false; - - // Don't do anything if these haven't been set yet - if (HttpPort != 0 && HttpsPort != 0) - { - // Need to restart if ports have changed - if (ServerConfigurationManager.Configuration.HttpServerPortNumber != HttpPort || - ServerConfigurationManager.Configuration.HttpsPortNumber != HttpsPort) - { - if (ServerConfigurationManager.Configuration.IsPortAuthorized) - { - ServerConfigurationManager.Configuration.IsPortAuthorized = false; - ServerConfigurationManager.SaveConfiguration(); - - requiresRestart = true; - } - } - } - - if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase)) - { - requiresRestart = true; - } - - if (!string.Equals(CertificatePath, GetCertificatePath(false), StringComparison.OrdinalIgnoreCase)) - { - requiresRestart = true; - } - - if (requiresRestart) - { - NotifyPendingRestart(); - } - } - - /// <summary> - /// Restarts this instance. - /// </summary> - public override async Task Restart() - { - if (!CanSelfRestart) - { - throw new PlatformNotSupportedException("The server is unable to self-restart. Please restart manually."); - } - - try - { - await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending server restart notification", ex); - } - - Logger.Info("Calling NativeApp.Restart"); - - NativeApp.Restart(_startupOptions); - } - - /// <summary> - /// Gets or sets a value indicating whether this instance can self update. - /// </summary> - /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value> - public override bool CanSelfUpdate - { - get - { -#if DEBUG - return false; -#endif -#pragma warning disable 162 - return NativeApp.CanSelfUpdate; -#pragma warning restore 162 - } - } - - /// <summary> - /// Gets the composable part assemblies. - /// </summary> - /// <returns>IEnumerable{Assembly}.</returns> - protected override IEnumerable<Assembly> GetComposablePartAssemblies() - { - var list = GetPluginAssemblies() - .ToList(); - - // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that - // This will prevent the .dll file from getting locked, and allow us to replace it when needed - - // Include composable parts in the Api assembly - list.Add(typeof(ApiEntryPoint).Assembly); - - // Include composable parts in the Dashboard assembly - list.Add(typeof(DashboardService).Assembly); - - // Include composable parts in the Model assembly - list.Add(typeof(SystemInfo).Assembly); - - // Include composable parts in the Common assembly - list.Add(typeof(IApplicationHost).Assembly); - - // Include composable parts in the Controller assembly - list.Add(typeof(IServerApplicationHost).Assembly); - - // Include composable parts in the Providers assembly - list.Add(typeof(ProviderUtils).Assembly); - - // Common implementations - list.Add(typeof(TaskManager).Assembly); - - // Server implementations - list.Add(typeof(ServerApplicationPaths).Assembly); - - // MediaEncoding - list.Add(typeof(MediaEncoder).Assembly); - - // Dlna - list.Add(typeof(DlnaEntryPoint).Assembly); - - // Local metadata - list.Add(typeof(BoxSetXmlSaver).Assembly); - - // Xbmc - list.Add(typeof(ArtistNfoProvider).Assembly); - - list.AddRange(NativeApp.GetAssembliesWithParts()); - - // Include composable parts in the running assembly - list.Add(GetType().Assembly); - - return list; - } - - /// <summary> - /// Gets the plugin assemblies. - /// </summary> - /// <returns>IEnumerable{Assembly}.</returns> - private IEnumerable<Assembly> GetPluginAssemblies() - { - try - { - return Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) - .Select(LoadAssembly) - .Where(a => a != null) - .ToList(); - } - catch (DirectoryNotFoundException) - { - return new List<Assembly>(); - } - } - - /// <summary> - /// Gets the system status. - /// </summary> - /// <returns>SystemInfo.</returns> - public async Task<SystemInfo> GetSystemInfo() - { - var localAddress = await GetLocalApiUrl().ConfigureAwait(false); - - return new SystemInfo - { - HasPendingRestart = HasPendingRestart, - Version = ApplicationVersion.ToString(), - IsNetworkDeployed = CanSelfUpdate, - WebSocketPortNumber = HttpPort, - FailedPluginAssemblies = FailedAssemblies.ToList(), - InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToList(), - CompletedInstallations = InstallationManager.CompletedInstallations.ToList(), - Id = SystemId, - ProgramDataPath = ApplicationPaths.ProgramDataPath, - LogPath = ApplicationPaths.LogDirectoryPath, - ItemsByNamePath = ApplicationPaths.ItemsByNamePath, - InternalMetadataPath = ApplicationPaths.InternalMetadataPath, - CachePath = ApplicationPaths.CachePath, - MacAddress = GetMacAddress(), - HttpServerPortNumber = HttpPort, - SupportsHttps = SupportsHttps, - HttpsPortNumber = HttpsPort, - OperatingSystem = NativeApp.Environment.OperatingSystem.ToString(), - OperatingSystemDisplayName = OperatingSystemDisplayName, - CanSelfRestart = CanSelfRestart, - CanSelfUpdate = CanSelfUpdate, - WanAddress = ConnectManager.WanApiAddress, - HasUpdateAvailable = HasUpdateAvailable, - SupportsAutoRunAtStartup = SupportsAutoRunAtStartup, - TranscodingTempPath = ApplicationPaths.TranscodingTempPath, - IsRunningAsService = IsRunningAsService, - SupportsRunningAsService = SupportsRunningAsService, - ServerName = FriendlyName, - LocalAddress = localAddress, - SupportsLibraryMonitor = SupportsLibraryMonitor, - EncoderLocationType = MediaEncoder.EncoderLocationType, - SystemArchitecture = NativeApp.Environment.SystemArchitecture, - SystemUpdateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel, - PackageName = _startupOptions.GetOption("-package") - }; - } - - public bool EnableHttps - { - get - { - return SupportsHttps && ServerConfigurationManager.Configuration.EnableHttps; - } - } - - public bool SupportsHttps - { - get { return !string.IsNullOrWhiteSpace(HttpServer.CertificatePath); } - } - - public async Task<string> GetLocalApiUrl() - { - try - { - // Return the first matched address, if found, or the first known local address - var address = (await GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !IPAddress.IsLoopback(i)); - - if (address != null) - { - return GetLocalApiUrl(address); - } - - return null; - } - catch (Exception ex) - { - Logger.ErrorException("Error getting local Ip address information", ex); - } - - return null; - } - - public string GetLocalApiUrl(IPAddress ipAddress) - { - if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) - { - return GetLocalApiUrl("[" + ipAddress + "]"); - } - - return GetLocalApiUrl(ipAddress.ToString()); - } - - public string GetLocalApiUrl(string host) - { - return string.Format("http://{0}:{1}", - host, - HttpPort.ToString(CultureInfo.InvariantCulture)); - } - - public async Task<List<IPAddress>> GetLocalIpAddresses() - { - var addresses = NetworkManager.GetLocalIpAddresses().ToList(); - var list = new List<IPAddress>(); - - foreach (var address in addresses) - { - var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false); - if (valid) - { - list.Add(address); - } - } - - return list; - } - - private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase); - private DateTime _lastAddressCacheClear; - private async Task<bool> IsIpAddressValidAsync(IPAddress address) - { - if (IPAddress.IsLoopback(address)) - { - return true; - } - - var apiUrl = GetLocalApiUrl(address); - apiUrl += "/system/ping"; - - if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 10) - { - _lastAddressCacheClear = DateTime.UtcNow; - _validAddressResults.Clear(); - } - - bool cachedResult; - if (_validAddressResults.TryGetValue(apiUrl, out cachedResult)) - { - return cachedResult; - } - - try - { - using (var response = await HttpClient.SendAsync(new HttpRequestOptions - { - Url = apiUrl, - LogErrorResponseBody = false, - LogErrors = false, - LogRequest = false, - TimeoutMs = 30000, - BufferContent = false - - }, "POST").ConfigureAwait(false)) - { - using (var reader = new StreamReader(response.Content)) - { - var result = reader.ReadToEnd(); - var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase); - - _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid); - //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid); - return valid; - } - } - } - catch - { - //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false); - - _validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false); - return false; - } - } - - public string FriendlyName - { - get - { - return string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName) - ? Environment.MachineName - : ServerConfigurationManager.Configuration.ServerName; - } - } - - public int HttpPort { get; private set; } - - public int HttpsPort { get; private set; } - - /// <summary> - /// Gets the mac address. - /// </summary> - /// <returns>System.String.</returns> - private string GetMacAddress() - { - try - { - return NetworkManager.GetMacAddress(); - } - catch (Exception ex) - { - Logger.ErrorException("Error getting mac address", ex); - return null; - } - } - - /// <summary> - /// Shuts down. - /// </summary> - public override async Task Shutdown() - { - try - { - await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending server shutdown notification", ex); - } - - NativeApp.Shutdown(); - } - - /// <summary> - /// Registers the server with administrator access. - /// </summary> - private void RegisterServerWithAdministratorAccess() - { - Logger.Info("Requesting administrative access to authorize http server"); - - try - { - NativeApp.AuthorizeServer( - UdpServerEntryPoint.PortNumber, - ServerConfigurationManager.Configuration.HttpServerPortNumber, - ServerConfigurationManager.Configuration.HttpsPortNumber, - ConfigurationManager.CommonApplicationPaths.ApplicationPath, - ConfigurationManager.CommonApplicationPaths.TempDirectory); - } - catch (Exception ex) - { - Logger.ErrorException("Error authorizing server", ex); - } - } - - public event EventHandler HasUpdateAvailableChanged; - - private bool _hasUpdateAvailable; - public bool HasUpdateAvailable - { - get { return _hasUpdateAvailable; } - set - { - var fireEvent = value && !_hasUpdateAvailable; - - _hasUpdateAvailable = value; - - if (fireEvent) - { - EventHelper.FireEventIfNotNull(HasUpdateAvailableChanged, this, EventArgs.Empty, Logger); - } - } - } - - /// <summary> - /// Checks for update. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task{CheckForUpdateResult}.</returns> - public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress) - { - var cacheLength = TimeSpan.FromHours(3); - var updateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel; - - if (updateLevel == PackageVersionClass.Beta) - { - cacheLength = TimeSpan.FromHours(1); - } - else if (updateLevel == PackageVersionClass.Dev) - { - cacheLength = TimeSpan.FromMinutes(5); - } - - var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser", "Emby", ApplicationVersion, updateLevel, _releaseAssetFilename, - "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false); - - HasUpdateAvailable = result.IsUpdateAvailable; - - return result; - } - - /// <summary> - /// Updates the application. - /// </summary> - /// <param name="package">The package that contains the update</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress) - { - await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false); - - HasUpdateAvailable = false; - - OnApplicationUpdated(package); - } - - /// <summary> - /// Configures the automatic run at startup. - /// </summary> - /// <param name="autorun">if set to <c>true</c> [autorun].</param> - protected override void ConfigureAutoRunAtStartup(bool autorun) - { - if (SupportsAutoRunAtStartup) - { - NativeApp.ConfigureAutoRun(autorun); - } - } - - /// <summary> - /// This returns localhost in the case of no external dns, and the hostname if the - /// dns is prefixed with a valid Uri prefix. - /// </summary> - /// <param name="externalDns">The external dns prefix to get the hostname of.</param> - /// <returns>The hostname in <paramref name="externalDns"/></returns> - private static string GetHostnameFromExternalDns(string externalDns) - { - if (string.IsNullOrWhiteSpace(externalDns)) - { - return "localhost"; - } - - try - { - return new Uri(externalDns).Host; - } - catch - { - return externalDns; - } - } - - public void LaunchUrl(string url) - { - NativeApp.LaunchUrl(url); - } - - public void EnableLoopback(string appName) - { - NativeApp.EnableLoopback(appName); - } - } -}