commit
e229f6d9bb
|
@ -114,6 +114,11 @@ namespace Emby.Server.Implementations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly string[] _relevantEnvVarPrefixes = { "JELLYFIN_", "DOTNET_", "ASPNETCORE_" };
|
private static readonly string[] _relevantEnvVarPrefixes = { "JELLYFIN_", "DOTNET_", "ASPNETCORE_" };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The disposable parts.
|
||||||
|
/// </summary>
|
||||||
|
private readonly List<IDisposable> _disposableParts = new List<IDisposable>();
|
||||||
|
|
||||||
private readonly IFileSystem _fileSystemManager;
|
private readonly IFileSystem _fileSystemManager;
|
||||||
private readonly IConfiguration _startupConfig;
|
private readonly IConfiguration _startupConfig;
|
||||||
private readonly IXmlSerializer _xmlSerializer;
|
private readonly IXmlSerializer _xmlSerializer;
|
||||||
|
@ -125,104 +130,15 @@ namespace Emby.Server.Implementations
|
||||||
private ISessionManager _sessionManager;
|
private ISessionManager _sessionManager;
|
||||||
private string[] _urlPrefixes;
|
private string[] _urlPrefixes;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this instance can self restart.
|
|
||||||
/// </summary>
|
|
||||||
public bool CanSelfRestart => _startupOptions.RestartPath != null;
|
|
||||||
|
|
||||||
public bool CoreStartupHasCompleted { get; private set; }
|
|
||||||
|
|
||||||
public virtual bool CanLaunchWebBrowser
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!Environment.UserInteractive)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_startupOptions.IsService)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OperatingSystem.IsWindows() || OperatingSystem.IsMacOS();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="INetworkManager"/> singleton instance.
|
|
||||||
/// </summary>
|
|
||||||
public INetworkManager NetManager { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Occurs when [has pending restart changed].
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler HasPendingRestartChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this instance has changes that require the entire application to restart.
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
|
|
||||||
public bool HasPendingRestart { get; private set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsShuttingDown { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the logger.
|
|
||||||
/// </summary>
|
|
||||||
protected ILogger<ApplicationHost> Logger { get; }
|
|
||||||
|
|
||||||
protected IServiceCollection ServiceCollection { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the logger factory.
|
|
||||||
/// </summary>
|
|
||||||
protected ILoggerFactory LoggerFactory { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the application paths.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The application paths.</value>
|
|
||||||
protected IServerApplicationPaths ApplicationPaths { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets all concrete types.
|
/// Gets or sets all concrete types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>All concrete types.</value>
|
/// <value>All concrete types.</value>
|
||||||
private Type[] _allConcreteTypes;
|
private Type[] _allConcreteTypes;
|
||||||
|
|
||||||
/// <summary>
|
private DeviceId _deviceId;
|
||||||
/// The disposable parts.
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<IDisposable> _disposableParts = new List<IDisposable>();
|
|
||||||
|
|
||||||
/// <summary>
|
private bool _disposed = false;
|
||||||
/// Gets or sets the configuration manager.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The configuration manager.</value>
|
|
||||||
public ServerConfigurationManager ConfigurationManager { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the service provider.
|
|
||||||
/// </summary>
|
|
||||||
public IServiceProvider ServiceProvider { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the http port for the webhost.
|
|
||||||
/// </summary>
|
|
||||||
public int HttpPort { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the https port for the webhost.
|
|
||||||
/// </summary>
|
|
||||||
public int HttpsPort { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of the PublishedServerUrl setting.
|
|
||||||
/// </summary>
|
|
||||||
public string PublishedServerUrl => _startupOptions.PublishedServerUrl ?? _startupConfig[UdpServer.AddressOverrideConfigKey];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
|
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
|
||||||
|
@ -265,6 +181,143 @@ namespace Emby.Server.Implementations
|
||||||
ApplicationVersion);
|
ApplicationVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when [has pending restart changed].
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler HasPendingRestartChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance can self restart.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanSelfRestart => _startupOptions.RestartPath != null;
|
||||||
|
|
||||||
|
public bool CoreStartupHasCompleted { get; private set; }
|
||||||
|
|
||||||
|
public virtual bool CanLaunchWebBrowser
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!Environment.UserInteractive)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_startupOptions.IsService)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OperatingSystem.IsWindows() || OperatingSystem.IsMacOS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="INetworkManager"/> singleton instance.
|
||||||
|
/// </summary>
|
||||||
|
public INetworkManager NetManager { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance has changes that require the entire application to restart.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
|
||||||
|
public bool HasPendingRestart { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsShuttingDown { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the logger.
|
||||||
|
/// </summary>
|
||||||
|
protected ILogger<ApplicationHost> Logger { get; }
|
||||||
|
|
||||||
|
protected IServiceCollection ServiceCollection { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the logger factory.
|
||||||
|
/// </summary>
|
||||||
|
protected ILoggerFactory LoggerFactory { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the application paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application paths.</value>
|
||||||
|
protected IServerApplicationPaths ApplicationPaths { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the configuration manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The configuration manager.</value>
|
||||||
|
public ServerConfigurationManager ConfigurationManager { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the service provider.
|
||||||
|
/// </summary>
|
||||||
|
public IServiceProvider ServiceProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the http port for the webhost.
|
||||||
|
/// </summary>
|
||||||
|
public int HttpPort { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the https port for the webhost.
|
||||||
|
/// </summary>
|
||||||
|
public int HttpsPort { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the PublishedServerUrl setting.
|
||||||
|
/// </summary>
|
||||||
|
public string PublishedServerUrl => _startupOptions.PublishedServerUrl ?? _startupConfig[UdpServer.AddressOverrideConfigKey];
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Version ApplicationVersion { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string ApplicationVersionString { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current application user agent.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application user agent.</value>
|
||||||
|
public string ApplicationUserAgent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the email address for use within a comment section of a user agent field.
|
||||||
|
/// Presently used to provide contact information to MusicBrainz service.
|
||||||
|
/// </summary>
|
||||||
|
public string ApplicationUserAgentAddress => "team@jellyfin.org";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current application name.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The application name.</value>
|
||||||
|
public string ApplicationProductName { get; } = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName;
|
||||||
|
|
||||||
|
public string SystemId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_deviceId ??= new DeviceId(ApplicationPaths, LoggerFactory);
|
||||||
|
|
||||||
|
return _deviceId.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string Name => ApplicationProductName;
|
||||||
|
|
||||||
|
private CertificateInfo CertificateInfo { get; set; }
|
||||||
|
|
||||||
|
public X509Certificate2 Certificate { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool ListenWithHttps => Certificate != null && ConfigurationManager.GetNetworkConfiguration().EnableHttps;
|
||||||
|
|
||||||
|
public string FriendlyName =>
|
||||||
|
string.IsNullOrEmpty(ConfigurationManager.Configuration.ServerName)
|
||||||
|
? Environment.MachineName
|
||||||
|
: ConfigurationManager.Configuration.ServerName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporary function to migration network settings out of system.xml and into network.xml.
|
/// Temporary function to migration network settings out of system.xml and into network.xml.
|
||||||
/// TODO: remove at the point when a fixed migration path has been decided upon.
|
/// TODO: remove at the point when a fixed migration path has been decided upon.
|
||||||
|
@ -297,45 +350,6 @@ namespace Emby.Server.Implementations
|
||||||
.Replace(appPaths.InternalMetadataPath, appPaths.VirtualInternalMetadataPath, StringComparison.OrdinalIgnoreCase);
|
.Replace(appPaths.InternalMetadataPath, appPaths.VirtualInternalMetadataPath, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Version ApplicationVersion { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string ApplicationVersionString { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current application user agent.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The application user agent.</value>
|
|
||||||
public string ApplicationUserAgent { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the email address for use within a comment section of a user agent field.
|
|
||||||
/// Presently used to provide contact information to MusicBrainz service.
|
|
||||||
/// </summary>
|
|
||||||
public string ApplicationUserAgentAddress => "team@jellyfin.org";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current application name.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The application name.</value>
|
|
||||||
public string ApplicationProductName { get; } = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName;
|
|
||||||
|
|
||||||
private DeviceId _deviceId;
|
|
||||||
|
|
||||||
public string SystemId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_deviceId ??= new DeviceId(ApplicationPaths, LoggerFactory);
|
|
||||||
|
|
||||||
return _deviceId.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string Name => ApplicationProductName;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of type and resolves all constructor dependencies.
|
/// Creates an instance of type and resolves all constructor dependencies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -857,10 +871,6 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CertificateInfo CertificateInfo { get; set; }
|
|
||||||
|
|
||||||
public X509Certificate2 Certificate { get; private set; }
|
|
||||||
|
|
||||||
private IEnumerable<string> GetUrlPrefixes()
|
private IEnumerable<string> GetUrlPrefixes()
|
||||||
{
|
{
|
||||||
var hosts = new[] { "+" };
|
var hosts = new[] { "+" };
|
||||||
|
@ -1114,9 +1124,6 @@ namespace Emby.Server.Implementations
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool ListenWithHttps => Certificate != null && ConfigurationManager.GetNetworkConfiguration().EnableHttps;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string GetSmartApiUrl(IPAddress remoteAddr, int? port = null)
|
public string GetSmartApiUrl(IPAddress remoteAddr, int? port = null)
|
||||||
{
|
{
|
||||||
|
@ -1203,14 +1210,7 @@ namespace Emby.Server.Implementations
|
||||||
}.ToString().TrimEnd('/');
|
}.ToString().TrimEnd('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FriendlyName =>
|
/// <inheritdoc />
|
||||||
string.IsNullOrEmpty(ConfigurationManager.Configuration.ServerName)
|
|
||||||
? Environment.MachineName
|
|
||||||
: ConfigurationManager.Configuration.ServerName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shuts down.
|
|
||||||
/// </summary>
|
|
||||||
public async Task Shutdown()
|
public async Task Shutdown()
|
||||||
{
|
{
|
||||||
if (IsShuttingDown)
|
if (IsShuttingDown)
|
||||||
|
@ -1248,41 +1248,7 @@ namespace Emby.Server.Implementations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void LaunchUrl(string url)
|
/// <inheritdoc />
|
||||||
{
|
|
||||||
if (!CanLaunchWebBrowser)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = url,
|
|
||||||
UseShellExecute = true,
|
|
||||||
ErrorDialog = false
|
|
||||||
},
|
|
||||||
EnableRaisingEvents = true
|
|
||||||
};
|
|
||||||
process.Exited += (sender, args) => ((Process)sender).Dispose();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
process.Start();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, "Error launching url: {url}", url);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disposed = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
|
|
@ -196,8 +196,8 @@ namespace Emby.Server.Implementations.Collections
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids)
|
public Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds)
|
||||||
=> AddToCollectionAsync(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem)));
|
=> AddToCollectionAsync(collectionId, itemIds, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem)));
|
||||||
|
|
||||||
private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1902,12 +1902,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets chapters for an item.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <returns>IEnumerable{ChapterInfo}.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">id</exception>
|
|
||||||
public List<ChapterInfo> GetChapters(BaseItem item)
|
public List<ChapterInfo> GetChapters(BaseItem item)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
@ -1930,13 +1925,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets a single chapter for an item.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <param name="index">The index.</param>
|
|
||||||
/// <returns>ChapterInfo.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException">id</exception>
|
|
||||||
public ChapterInfo GetChapter(BaseItem item, int index)
|
public ChapterInfo GetChapter(BaseItem item, int index)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
@ -2048,7 +2037,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
for (var i = startIndex; i < endIndex; i++)
|
for (var i = startIndex; i < endIndex; i++)
|
||||||
{
|
{
|
||||||
insertText.AppendFormat("(@ItemId, @ChapterIndex{0}, @StartPositionTicks{0}, @Name{0}, @ImagePath{0}, @ImageDateModified{0}),", i.ToString(CultureInfo.InvariantCulture));
|
insertText.AppendFormat(CultureInfo.InvariantCulture, "(@ItemId, @ChapterIndex{0}, @StartPositionTicks{0}, @Name{0}, @ImagePath{0}, @ImageDateModified{0}),", i.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
insertText.Length -= 1; // Remove last ,
|
insertText.Length -= 1; // Remove last ,
|
||||||
|
|
|
@ -129,19 +129,17 @@ namespace Emby.Server.Implementations.Data
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Saves the user data.
|
public void SaveUserData(long userId, string key, UserItemData userData, CancellationToken cancellationToken)
|
||||||
/// </summary>
|
|
||||||
public void SaveUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (userData == null)
|
if (userData == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(userData));
|
throw new ArgumentNullException(nameof(userData));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalUserId <= 0)
|
if (userId <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(internalUserId));
|
throw new ArgumentNullException(nameof(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(key))
|
if (string.IsNullOrEmpty(key))
|
||||||
|
@ -149,22 +147,23 @@ namespace Emby.Server.Implementations.Data
|
||||||
throw new ArgumentNullException(nameof(key));
|
throw new ArgumentNullException(nameof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistUserData(internalUserId, key, userData, cancellationToken);
|
PersistUserData(userId, key, userData, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveAllUserData(long internalUserId, UserItemData[] userData, CancellationToken cancellationToken)
|
/// <inheritdoc />
|
||||||
|
public void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (userData == null)
|
if (userData == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(userData));
|
throw new ArgumentNullException(nameof(userData));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalUserId <= 0)
|
if (userId <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(internalUserId));
|
throw new ArgumentNullException(nameof(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistAllUserData(internalUserId, userData, cancellationToken);
|
PersistAllUserData(userId, userData, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -263,19 +262,19 @@ namespace Emby.Server.Implementations.Data
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user data.
|
/// Gets the user data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalUserId">The user id.</param>
|
/// <param name="userId">The user id.</param>
|
||||||
/// <param name="key">The key.</param>
|
/// <param name="key">The key.</param>
|
||||||
/// <returns>Task{UserItemData}.</returns>
|
/// <returns>Task{UserItemData}.</returns>
|
||||||
/// <exception cref="ArgumentNullException">
|
/// <exception cref="ArgumentNullException">
|
||||||
/// userId
|
/// userId
|
||||||
/// or
|
/// or
|
||||||
/// key
|
/// key.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public UserItemData GetUserData(long internalUserId, string key)
|
public UserItemData GetUserData(long userId, string key)
|
||||||
{
|
{
|
||||||
if (internalUserId <= 0)
|
if (userId <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(internalUserId));
|
throw new ArgumentNullException(nameof(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(key))
|
if (string.IsNullOrEmpty(key))
|
||||||
|
@ -287,7 +286,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId"))
|
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@UserId", internalUserId);
|
statement.TryBind("@UserId", userId);
|
||||||
statement.TryBind("@Key", key);
|
statement.TryBind("@Key", key);
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
foreach (var row in statement.ExecuteQuery())
|
||||||
|
@ -300,7 +299,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserItemData GetUserData(long internalUserId, List<string> keys)
|
public UserItemData GetUserData(long userId, List<string> keys)
|
||||||
{
|
{
|
||||||
if (keys == null)
|
if (keys == null)
|
||||||
{
|
{
|
||||||
|
@ -312,19 +311,19 @@ namespace Emby.Server.Implementations.Data
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetUserData(internalUserId, keys[0]);
|
return GetUserData(userId, keys[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return all user-data associated with the given user.
|
/// Return all user-data associated with the given user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="internalUserId">The internal user id.</param>
|
/// <param name="userId">The internal user id.</param>
|
||||||
/// <returns>The list of user item data.</returns>
|
/// <returns>The list of user item data.</returns>
|
||||||
public List<UserItemData> GetAllUserData(long internalUserId)
|
public List<UserItemData> GetAllUserData(long userId)
|
||||||
{
|
{
|
||||||
if (internalUserId <= 0)
|
if (userId <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(internalUserId));
|
throw new ArgumentNullException(nameof(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<UserItemData>();
|
var list = new List<UserItemData>();
|
||||||
|
@ -333,7 +332,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId"))
|
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@UserId", internalUserId);
|
statement.TryBind("@UserId", userId);
|
||||||
|
|
||||||
foreach (var row in statement.ExecuteQuery())
|
foreach (var row in statement.ExecuteQuery())
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,8 +51,6 @@ namespace Emby.Server.Implementations.Dto
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
|
private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
|
||||||
|
|
||||||
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
|
|
||||||
|
|
||||||
public DtoService(
|
public DtoService(
|
||||||
ILogger<DtoService> logger,
|
ILogger<DtoService> logger,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
|
@ -75,6 +73,8 @@ namespace Emby.Server.Implementations.Dto
|
||||||
_livetvManagerFactory = livetvManagerFactory;
|
_livetvManagerFactory = livetvManagerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
|
public IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
|
||||||
{
|
{
|
||||||
|
@ -507,7 +507,6 @@ namespace Emby.Server.Implementations.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto">The dto.</param>
|
/// <param name="dto">The dto.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private void AttachPeople(BaseItemDto dto, BaseItem item)
|
private void AttachPeople(BaseItemDto dto, BaseItem item)
|
||||||
{
|
{
|
||||||
// Ordering by person type to ensure actors and artists are at the front.
|
// Ordering by person type to ensure actors and artists are at the front.
|
||||||
|
@ -616,7 +615,6 @@ namespace Emby.Server.Implementations.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto">The dto.</param>
|
/// <param name="dto">The dto.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private void AttachStudios(BaseItemDto dto, BaseItem item)
|
private void AttachStudios(BaseItemDto dto, BaseItem item)
|
||||||
{
|
{
|
||||||
dto.Studios = item.Studios
|
dto.Studios = item.Studios
|
||||||
|
@ -1313,9 +1311,12 @@ namespace Emby.Server.Implementations.Dto
|
||||||
|
|
||||||
var imageTags = dto.ImageTags;
|
var imageTags = dto.ImageTags;
|
||||||
|
|
||||||
while (((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0) || parent is Series) &&
|
while ((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0)
|
||||||
(parent ??= (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null)
|
|| (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0)
|
||||||
|
|| (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0)
|
||||||
|
|| parent is Series)
|
||||||
{
|
{
|
||||||
|
parent ??= isFirst ? GetImageDisplayParent(item, item) ?? owner : parent;
|
||||||
if (parent == null)
|
if (parent == null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -1395,7 +1396,6 @@ namespace Emby.Server.Implementations.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto">The dto.</param>
|
/// <param name="dto">The dto.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>Task.</returns>
|
|
||||||
public void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
|
public void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
|
||||||
{
|
{
|
||||||
dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
|
dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
|
||||||
|
|
|
@ -423,7 +423,7 @@ namespace Emby.Server.Implementations.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly)
|
public virtual void SetAttributes(string path, bool isHidden, bool readOnly)
|
||||||
{
|
{
|
||||||
if (!OperatingSystem.IsWindows())
|
if (!OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
|
@ -437,14 +437,14 @@ namespace Emby.Server.Implementations.IO
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.IsReadOnly == isReadOnly && info.IsHidden == isHidden)
|
if (info.IsReadOnly == readOnly && info.IsHidden == isHidden)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributes = File.GetAttributes(path);
|
var attributes = File.GetAttributes(path);
|
||||||
|
|
||||||
if (isReadOnly)
|
if (readOnly)
|
||||||
{
|
{
|
||||||
attributes = attributes | FileAttributes.ReadOnly;
|
attributes = attributes | FileAttributes.ReadOnly;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.Images
|
||||||
|
|
||||||
public int Order => 0;
|
public int Order => 0;
|
||||||
|
|
||||||
protected virtual bool Supports(BaseItem _) => true;
|
protected virtual bool Supports(BaseItem item) => true;
|
||||||
|
|
||||||
public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1761,22 +1761,20 @@ namespace Emby.Server.Implementations.Library
|
||||||
return orderedItems ?? items;
|
return orderedItems ?? items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderByList)
|
public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderBy)
|
||||||
{
|
{
|
||||||
var isFirst = true;
|
var isFirst = true;
|
||||||
|
|
||||||
IOrderedEnumerable<BaseItem> orderedItems = null;
|
IOrderedEnumerable<BaseItem> orderedItems = null;
|
||||||
|
|
||||||
foreach (var orderBy in orderByList)
|
foreach (var (name, sortOrder) in orderBy)
|
||||||
{
|
{
|
||||||
var comparer = GetComparer(orderBy.Item1, user);
|
var comparer = GetComparer(name, user);
|
||||||
if (comparer == null)
|
if (comparer == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortOrder = orderBy.Item2;
|
|
||||||
|
|
||||||
if (isFirst)
|
if (isFirst)
|
||||||
{
|
{
|
||||||
orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, comparer) : items.OrderBy(i => i, comparer);
|
orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, comparer) : items.OrderBy(i => i, comparer);
|
||||||
|
@ -3076,9 +3074,9 @@ namespace Emby.Server.Implementations.Library
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
|
public void AddMediaPath(string virtualFolderName, MediaPathInfo mediaPath)
|
||||||
{
|
{
|
||||||
AddMediaPathInternal(virtualFolderName, pathInfo, true);
|
AddMediaPathInternal(virtualFolderName, mediaPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
|
private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
|
||||||
|
@ -3131,11 +3129,11 @@ namespace Emby.Server.Implementations.Library
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
|
public void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath)
|
||||||
{
|
{
|
||||||
if (pathInfo == null)
|
if (mediaPath == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(pathInfo));
|
throw new ArgumentNullException(nameof(mediaPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
|
||||||
|
@ -3148,9 +3146,9 @@ namespace Emby.Server.Implementations.Library
|
||||||
var list = libraryOptions.PathInfos.ToList();
|
var list = libraryOptions.PathInfos.ToList();
|
||||||
foreach (var originalPathInfo in list)
|
foreach (var originalPathInfo in list)
|
||||||
{
|
{
|
||||||
if (string.Equals(pathInfo.Path, originalPathInfo.Path, StringComparison.Ordinal))
|
if (string.Equals(mediaPath.Path, originalPathInfo.Path, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
originalPathInfo.NetworkPath = pathInfo.NetworkPath;
|
originalPathInfo.NetworkPath = mediaPath.NetworkPath;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,10 @@ namespace Emby.Server.Implementations.Library
|
||||||
return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions)).ToList();
|
return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseItem> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
|
/// <inheritdoc />
|
||||||
|
public List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions)
|
||||||
{
|
{
|
||||||
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
return GetInstantMixFromGenres(artist.Genres, user, dtoOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
|
public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
|
||||||
|
|
|
@ -21,13 +21,13 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||||
public abstract class BaseVideoResolver<T> : MediaBrowser.Controller.Resolvers.ItemResolver<T>
|
public abstract class BaseVideoResolver<T> : MediaBrowser.Controller.Resolvers.ItemResolver<T>
|
||||||
where T : Video, new()
|
where T : Video, new()
|
||||||
{
|
{
|
||||||
protected readonly ILibraryManager LibraryManager;
|
|
||||||
|
|
||||||
protected BaseVideoResolver(ILibraryManager libraryManager)
|
protected BaseVideoResolver(ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
LibraryManager = libraryManager;
|
LibraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ILibraryManager LibraryManager { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves the specified args.
|
/// Resolves the specified args.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -177,6 +177,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions options)
|
public UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions options)
|
||||||
{
|
{
|
||||||
var userData = GetUserData(user, item);
|
var userData = GetUserData(user, item);
|
||||||
|
@ -191,7 +192,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The data.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <returns>DtoUserItemData.</returns>
|
/// <returns>DtoUserItemData.</returns>
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
/// <exception cref="ArgumentNullException"><paramref name="data"/> is <c>null</c>.</exception>
|
||||||
private UserItemDataDto GetUserItemDataDto(UserItemData data)
|
private UserItemDataDto GetUserItemDataDto(UserItemData data)
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
|
@ -212,6 +213,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPositionTicks)
|
public bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPositionTicks)
|
||||||
{
|
{
|
||||||
var playedToCompletion = false;
|
var playedToCompletion = false;
|
||||||
|
|
|
@ -610,11 +610,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string> CreateTimer(TimerInfo timer, CancellationToken cancellationToken)
|
public Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId) ?
|
var existingTimer = string.IsNullOrWhiteSpace(info.ProgramId) ?
|
||||||
null :
|
null :
|
||||||
_timerProvider.GetTimerByProgramId(timer.ProgramId);
|
_timerProvider.GetTimerByProgramId(info.ProgramId);
|
||||||
|
|
||||||
if (existingTimer != null)
|
if (existingTimer != null)
|
||||||
{
|
{
|
||||||
|
@ -632,32 +632,32 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
LiveTvProgram programInfo = null;
|
LiveTvProgram programInfo = null;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(timer.ProgramId))
|
if (!string.IsNullOrWhiteSpace(info.ProgramId))
|
||||||
{
|
{
|
||||||
programInfo = GetProgramInfoFromCache(timer);
|
programInfo = GetProgramInfoFromCache(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (programInfo == null)
|
if (programInfo == null)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Unable to find program with Id {0}. Will search using start date", timer.ProgramId);
|
_logger.LogInformation("Unable to find program with Id {0}. Will search using start date", info.ProgramId);
|
||||||
programInfo = GetProgramInfoFromCache(timer.ChannelId, timer.StartDate);
|
programInfo = GetProgramInfoFromCache(info.ChannelId, info.StartDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (programInfo != null)
|
if (programInfo != null)
|
||||||
{
|
{
|
||||||
CopyProgramInfoToTimerInfo(programInfo, timer);
|
CopyProgramInfoToTimerInfo(programInfo, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.IsManual = true;
|
info.IsManual = true;
|
||||||
_timerProvider.Add(timer);
|
_timerProvider.Add(info);
|
||||||
|
|
||||||
TimerCreated?.Invoke(this, new GenericEventArgs<TimerInfo>(timer));
|
TimerCreated?.Invoke(this, new GenericEventArgs<TimerInfo>(info));
|
||||||
|
|
||||||
return Task.FromResult(timer.Id);
|
return Task.FromResult(info.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken)
|
public async Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -65,6 +65,8 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
|
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
|
||||||
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
|
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
|
||||||
|
|
||||||
|
private bool _disposed = false;
|
||||||
|
|
||||||
public LiveTvManager(
|
public LiveTvManager(
|
||||||
IServerConfigurationManager config,
|
IServerConfigurationManager config,
|
||||||
ILogger<LiveTvManager> logger,
|
ILogger<LiveTvManager> logger,
|
||||||
|
@ -520,7 +522,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tuple<LiveTvProgram, bool, bool> GetProgram(ProgramInfo info, Dictionary<Guid, LiveTvProgram> allExistingPrograms, LiveTvChannel channel, ChannelType channelType, string serviceName, CancellationToken cancellationToken)
|
private (LiveTvProgram item, bool isNew, bool isUpdated) GetProgram(ProgramInfo info, Dictionary<Guid, LiveTvProgram> allExistingPrograms, LiveTvChannel channel)
|
||||||
{
|
{
|
||||||
var id = _tvDtoService.GetInternalProgramId(info.Id);
|
var id = _tvDtoService.GetInternalProgramId(info.Id);
|
||||||
|
|
||||||
|
@ -559,8 +561,6 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
item.ParentId = channel.Id;
|
item.ParentId = channel.Id;
|
||||||
|
|
||||||
// item.ChannelType = channelType;
|
|
||||||
|
|
||||||
item.Audio = info.Audio;
|
item.Audio = info.Audio;
|
||||||
item.ChannelId = channel.Id;
|
item.ChannelId = channel.Id;
|
||||||
item.CommunityRating ??= info.CommunityRating;
|
item.CommunityRating ??= info.CommunityRating;
|
||||||
|
@ -772,7 +772,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
item.OnMetadataChanged();
|
item.OnMetadataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Tuple<LiveTvProgram, bool, bool>(item, isNew, isUpdated);
|
return (item, isNew, isUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
|
public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
|
||||||
|
@ -1187,14 +1187,14 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
foreach (var program in channelPrograms)
|
foreach (var program in channelPrograms)
|
||||||
{
|
{
|
||||||
var programTuple = GetProgram(program, existingPrograms, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken);
|
var programTuple = GetProgram(program, existingPrograms, currentChannel);
|
||||||
var programItem = programTuple.Item1;
|
var programItem = programTuple.item;
|
||||||
|
|
||||||
if (programTuple.Item2)
|
if (programTuple.isNew)
|
||||||
{
|
{
|
||||||
newPrograms.Add(programItem);
|
newPrograms.Add(programItem);
|
||||||
}
|
}
|
||||||
else if (programTuple.Item3)
|
else if (programTuple.isUpdated)
|
||||||
{
|
{
|
||||||
updatedPrograms.Add(programItem);
|
updatedPrograms.Add(programItem);
|
||||||
}
|
}
|
||||||
|
@ -1385,10 +1385,10 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
// var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
|
// var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
|
||||||
|
|
||||||
// return new QueryResult<BaseItem>
|
// return new QueryResult<BaseItem>
|
||||||
//{
|
// {
|
||||||
// Items = items,
|
// Items = items,
|
||||||
// TotalRecordCount = items.Length
|
// TotalRecordCount = items.Length
|
||||||
//};
|
// };
|
||||||
|
|
||||||
dtoOptions.Fields = dtoOptions.Fields.Concat(new[] { ItemFields.Tags }).Distinct().ToArray();
|
dtoOptions.Fields = dtoOptions.Fields.Concat(new[] { ItemFields.Tags }).Distinct().ToArray();
|
||||||
}
|
}
|
||||||
|
@ -1425,16 +1425,15 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> tuples, IReadOnlyList<ItemFields> fields, User user = null)
|
public Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, IReadOnlyList<ItemFields> fields, User user = null)
|
||||||
{
|
{
|
||||||
var programTuples = new List<Tuple<BaseItemDto, string, string>>();
|
var programTuples = new List<Tuple<BaseItemDto, string, string>>();
|
||||||
var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
|
var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
|
||||||
var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
|
var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
|
||||||
|
|
||||||
foreach (var tuple in tuples)
|
foreach (var (item, dto) in programs)
|
||||||
{
|
{
|
||||||
var program = (LiveTvProgram)tuple.Item1;
|
var program = (LiveTvProgram)item;
|
||||||
var dto = tuple.Item2;
|
|
||||||
|
|
||||||
dto.StartDate = program.StartDate;
|
dto.StartDate = program.StartDate;
|
||||||
dto.EpisodeTitle = program.EpisodeTitle;
|
dto.EpisodeTitle = program.EpisodeTitle;
|
||||||
|
@ -1871,11 +1870,11 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
return _libraryManager.GetItemById(internalChannelId);
|
return _libraryManager.GetItemById(internalChannelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> tuples, DtoOptions options, User user)
|
public void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
var channelIds = tuples.Select(i => i.Item2.Id).Distinct().ToArray();
|
var channelIds = items.Select(i => i.Item2.Id).Distinct().ToArray();
|
||||||
|
|
||||||
var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user)
|
var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
|
@ -1896,7 +1895,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
var addCurrentProgram = options.AddCurrentProgram;
|
var addCurrentProgram = options.AddCurrentProgram;
|
||||||
|
|
||||||
foreach (var tuple in tuples)
|
foreach (var tuple in items)
|
||||||
{
|
{
|
||||||
var dto = tuple.Item1;
|
var dto = tuple.Item1;
|
||||||
var channel = tuple.Item2;
|
var channel = tuple.Item2;
|
||||||
|
@ -2118,17 +2117,13 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _disposed = false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2324,20 +2319,20 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
_taskManager.CancelIfRunningAndQueue<RefreshGuideScheduledTask>();
|
_taskManager.CancelIfRunningAndQueue<RefreshGuideScheduledTask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelId, string providerChannelId)
|
public async Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber)
|
||||||
{
|
{
|
||||||
var config = GetConfiguration();
|
var config = GetConfiguration();
|
||||||
|
|
||||||
var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(providerId, i.Id, StringComparison.OrdinalIgnoreCase));
|
var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(providerId, i.Id, StringComparison.OrdinalIgnoreCase));
|
||||||
listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, tunerChannelId, StringComparison.OrdinalIgnoreCase)).ToArray();
|
listingsProviderInfo.ChannelMappings = listingsProviderInfo.ChannelMappings.Where(i => !string.Equals(i.Name, tunerChannelNumber, StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
|
|
||||||
if (!string.Equals(tunerChannelId, providerChannelId, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(tunerChannelNumber, providerChannelNumber, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var list = listingsProviderInfo.ChannelMappings.ToList();
|
var list = listingsProviderInfo.ChannelMappings.ToList();
|
||||||
list.Add(new NameValuePair
|
list.Add(new NameValuePair
|
||||||
{
|
{
|
||||||
Name = tunerChannelId,
|
Name = tunerChannelNumber,
|
||||||
Value = providerChannelId
|
Value = providerChannelNumber
|
||||||
});
|
});
|
||||||
listingsProviderInfo.ChannelMappings = list.ToArray();
|
listingsProviderInfo.ChannelMappings = list.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -2357,10 +2352,10 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
_taskManager.CancelIfRunningAndQueue<RefreshGuideScheduledTask>();
|
_taskManager.CancelIfRunningAndQueue<RefreshGuideScheduledTask>();
|
||||||
|
|
||||||
return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase));
|
return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelNumber, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> epgChannels)
|
public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> providerChannels)
|
||||||
{
|
{
|
||||||
var result = new TunerChannelMapping
|
var result = new TunerChannelMapping
|
||||||
{
|
{
|
||||||
|
@ -2373,7 +2368,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
result.Name = tunerChannel.Number + " " + result.Name;
|
result.Name = tunerChannel.Number + " " + result.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerChannel = EmbyTV.EmbyTV.Current.GetEpgChannelFromTunerChannel(mappings, tunerChannel, epgChannels);
|
var providerChannel = EmbyTV.EmbyTV.Current.GetEpgChannelFromTunerChannel(mappings, tunerChannel, providerChannels);
|
||||||
|
|
||||||
if (providerChannel != null)
|
if (providerChannel != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
return new List<MediaSourceInfo>();
|
return new List<MediaSourceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Task<ILiveStream> GetChannelStream(TunerHostInfo tuner, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
|
protected abstract Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
|
||||||
|
|
||||||
public async Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
public async Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,17 +95,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
public bool IsLegacyTuner { get; set; }
|
public bool IsLegacyTuner { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
|
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var lineup = await GetLineup(info, cancellationToken).ConfigureAwait(false);
|
var lineup = await GetLineup(tuner, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return lineup.Select(i => new HdHomerunChannelInfo
|
return lineup.Select(i => new HdHomerunChannelInfo
|
||||||
{
|
{
|
||||||
Name = i.GuideName,
|
Name = i.GuideName,
|
||||||
Number = i.GuideNumber,
|
Number = i.GuideNumber,
|
||||||
Id = GetChannelId(info, i),
|
Id = GetChannelId(tuner, i),
|
||||||
IsFavorite = i.Favorite,
|
IsFavorite = i.Favorite,
|
||||||
TunerHostId = info.Id,
|
TunerHostId = tuner.Id,
|
||||||
IsHD = i.HD,
|
IsHD = i.HD,
|
||||||
AudioCodec = i.AudioCodec,
|
AudioCodec = i.AudioCodec,
|
||||||
VideoCodec = i.VideoCodec,
|
VideoCodec = i.VideoCodec,
|
||||||
|
@ -496,57 +496,53 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
return mediaSource;
|
return mediaSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, ChannelInfo channelInfo, CancellationToken cancellationToken)
|
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, ChannelInfo channel, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var list = new List<MediaSourceInfo>();
|
var list = new List<MediaSourceInfo>();
|
||||||
|
|
||||||
var channelId = channelInfo.Id;
|
var channelId = channel.Id;
|
||||||
var hdhrId = GetHdHrIdFromChannelId(channelId);
|
var hdhrId = GetHdHrIdFromChannelId(channelId);
|
||||||
|
|
||||||
var hdHomerunChannelInfo = channelInfo as HdHomerunChannelInfo;
|
if (channel is HdHomerunChannelInfo hdHomerunChannelInfo && hdHomerunChannelInfo.IsLegacyTuner)
|
||||||
|
|
||||||
var isLegacyTuner = hdHomerunChannelInfo != null && hdHomerunChannelInfo.IsLegacyTuner;
|
|
||||||
|
|
||||||
if (isLegacyTuner)
|
|
||||||
{
|
{
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "native"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
var modelInfo = await GetModelInfo(tuner, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (modelInfo != null && modelInfo.SupportsTranscoding)
|
if (modelInfo != null && modelInfo.SupportsTranscoding)
|
||||||
{
|
{
|
||||||
if (info.AllowHWTranscoding)
|
if (tuner.AllowHWTranscoding)
|
||||||
{
|
{
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "heavy"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "heavy"));
|
||||||
|
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet540"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "internet540"));
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet480"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "internet480"));
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet360"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "internet360"));
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet240"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "internet240"));
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "mobile"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "mobile"));
|
||||||
}
|
}
|
||||||
|
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "native"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.Count == 0)
|
if (list.Count == 0)
|
||||||
{
|
{
|
||||||
list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
|
list.Add(GetMediaSource(tuner, hdhrId, channel, "native"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tunerCount = info.TunerCount;
|
var tunerCount = tunerHost.TunerCount;
|
||||||
|
|
||||||
if (tunerCount > 0)
|
if (tunerCount > 0)
|
||||||
{
|
{
|
||||||
var tunerHostId = info.Id;
|
var tunerHostId = tunerHost.Id;
|
||||||
var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
|
var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (liveStreams.Count() >= tunerCount)
|
if (liveStreams.Count() >= tunerCount)
|
||||||
|
@ -557,26 +553,26 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
var profile = streamId.Split('_')[0];
|
var profile = streamId.Split('_')[0];
|
||||||
|
|
||||||
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelInfo.Id, streamId, profile);
|
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channel.Id, streamId, profile);
|
||||||
|
|
||||||
var hdhrId = GetHdHrIdFromChannelId(channelInfo.Id);
|
var hdhrId = GetHdHrIdFromChannelId(channel.Id);
|
||||||
|
|
||||||
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
|
var hdhomerunChannel = channel as HdHomerunChannelInfo;
|
||||||
|
|
||||||
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
var modelInfo = await GetModelInfo(tunerHost, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!modelInfo.SupportsTranscoding)
|
if (!modelInfo.SupportsTranscoding)
|
||||||
{
|
{
|
||||||
profile = "native";
|
profile = "native";
|
||||||
}
|
}
|
||||||
|
|
||||||
var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
|
var mediaSource = GetMediaSource(tunerHost, hdhrId, channel, profile);
|
||||||
|
|
||||||
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
|
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
|
||||||
{
|
{
|
||||||
return new HdHomerunUdpStream(
|
return new HdHomerunUdpStream(
|
||||||
mediaSource,
|
mediaSource,
|
||||||
info,
|
tunerHost,
|
||||||
streamId,
|
streamId,
|
||||||
new LegacyHdHomerunChannelCommands(hdhomerunChannel.Path),
|
new LegacyHdHomerunChannelCommands(hdhomerunChannel.Path),
|
||||||
modelInfo.TunerCount,
|
modelInfo.TunerCount,
|
||||||
|
@ -592,7 +588,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
{
|
{
|
||||||
mediaSource.Protocol = MediaProtocol.Http;
|
mediaSource.Protocol = MediaProtocol.Http;
|
||||||
|
|
||||||
var httpUrl = channelInfo.Path;
|
var httpUrl = channel.Path;
|
||||||
|
|
||||||
// If raw was used, the tuner doesn't support params
|
// If raw was used, the tuner doesn't support params
|
||||||
if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
|
if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -604,7 +600,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
return new SharedHttpStream(
|
return new SharedHttpStream(
|
||||||
mediaSource,
|
mediaSource,
|
||||||
info,
|
tunerHost,
|
||||||
streamId,
|
streamId,
|
||||||
FileSystem,
|
FileSystem,
|
||||||
_httpClientFactory,
|
_httpClientFactory,
|
||||||
|
@ -616,7 +612,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
return new HdHomerunUdpStream(
|
return new HdHomerunUdpStream(
|
||||||
mediaSource,
|
mediaSource,
|
||||||
info,
|
tunerHost,
|
||||||
streamId,
|
streamId,
|
||||||
new HdHomerunChannelCommands(hdhomerunChannel.Number, profile),
|
new HdHomerunChannelCommands(hdhomerunChannel.Number, profile),
|
||||||
modelInfo.TunerCount,
|
modelInfo.TunerCount,
|
||||||
|
|
|
@ -71,12 +71,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
return ChannelIdPrefix + info.Url.GetMD5().ToString("N", CultureInfo.InvariantCulture);
|
return ChannelIdPrefix + info.Url.GetMD5().ToString("N", CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
|
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var channelIdPrefix = GetFullChannelIdPrefix(info);
|
var channelIdPrefix = GetFullChannelIdPrefix(tuner);
|
||||||
|
|
||||||
return await new M3uParser(Logger, _httpClientFactory)
|
return await new M3uParser(Logger, _httpClientFactory)
|
||||||
.Parse(info, channelIdPrefix, cancellationToken)
|
.Parse(tuner, channelIdPrefix, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,13 +96,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
return Task.FromResult(list);
|
return Task.FromResult(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tunerCount = info.TunerCount;
|
var tunerCount = tunerHost.TunerCount;
|
||||||
|
|
||||||
if (tunerCount > 0)
|
if (tunerCount > 0)
|
||||||
{
|
{
|
||||||
var tunerHostId = info.Id;
|
var tunerHostId = tunerHost.Id;
|
||||||
var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
|
var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (liveStreams.Count() >= tunerCount)
|
if (liveStreams.Count() >= tunerCount)
|
||||||
|
@ -111,7 +111,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sources = await GetChannelStreamMediaSources(info, channelInfo, cancellationToken).ConfigureAwait(false);
|
var sources = await GetChannelStreamMediaSources(tunerHost, channel, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var mediaSource = sources[0];
|
var mediaSource = sources[0];
|
||||||
|
|
||||||
|
@ -121,11 +121,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
|
|
||||||
if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClientFactory, Logger, Config, _appHost, _streamHelper);
|
return new SharedHttpStream(mediaSource, tunerHost, streamId, FileSystem, _httpClientFactory, Logger, Config, _appHost, _streamHelper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LiveStream(mediaSource, info, FileSystem, Logger, Config, _streamHelper);
|
return new LiveStream(mediaSource, tunerHost, FileSystem, Logger, Config, _streamHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Validate(TunerHostInfo info)
|
public async Task Validate(TunerHostInfo info)
|
||||||
|
@ -135,9 +135,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, ChannelInfo channelInfo, CancellationToken cancellationToken)
|
protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, ChannelInfo channel, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new List<MediaSourceInfo> { CreateMediaSourceInfo(info, channelInfo) });
|
return Task.FromResult(new List<MediaSourceInfo> { CreateMediaSourceInfo(tuner, channel) });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual MediaSourceInfo CreateMediaSourceInfo(TunerHostInfo info, ChannelInfo channel)
|
protected virtual MediaSourceInfo CreateMediaSourceInfo(TunerHostInfo info, ChannelInfo channel)
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace Emby.Server.Implementations.Net
|
||||||
{
|
{
|
||||||
public class SocketFactory : ISocketFactory
|
public class SocketFactory : ISocketFactory
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public ISocket CreateUdpBroadcastSocket(int localPort)
|
public ISocket CreateUdpBroadcastSocket(int localPort)
|
||||||
{
|
{
|
||||||
if (localPort < 0)
|
if (localPort < 0)
|
||||||
|
@ -35,11 +36,8 @@ namespace Emby.Server.Implementations.Net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
|
public ISocket CreateSsdpUdpSocket(IPAddress localIp, int localPort)
|
||||||
/// </summary>
|
|
||||||
/// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
|
|
||||||
public ISocket CreateSsdpUdpSocket(IPAddress localIpAddress, int localPort)
|
|
||||||
{
|
{
|
||||||
if (localPort < 0)
|
if (localPort < 0)
|
||||||
{
|
{
|
||||||
|
@ -53,8 +51,8 @@ namespace Emby.Server.Implementations.Net
|
||||||
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
|
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
|
||||||
|
|
||||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIpAddress));
|
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIp));
|
||||||
return new UdpSocket(retVal, localPort, localIpAddress);
|
return new UdpSocket(retVal, localPort, localIp);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -64,13 +62,7 @@ namespace Emby.Server.Implementations.Net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Creates a new UDP acceptSocket that is a member of the specified multicast IP address, and binds it to the specified local port.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ipAddress">The multicast IP address to make the acceptSocket a member of.</param>
|
|
||||||
/// <param name="multicastTimeToLive">The multicast time to live value for the acceptSocket.</param>
|
|
||||||
/// <param name="localPort">The number of the local port to bind to.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
|
public ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
|
||||||
{
|
{
|
||||||
if (ipAddress == null)
|
if (ipAddress == null)
|
||||||
|
|
|
@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.Net
|
||||||
return taskCompletion.Task;
|
return taskCompletion.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendToAsync(byte[] buffer, int offset, int size, IPEndPoint endPoint, CancellationToken cancellationToken)
|
public Task SendToAsync(byte[] buffer, int offset, int bytes, IPEndPoint endPoint, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ namespace Emby.Server.Implementations.Net
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = BeginSendTo(buffer, offset, size, endPoint, new AsyncCallback(callback), null);
|
var result = BeginSendTo(buffer, offset, bytes, endPoint, new AsyncCallback(callback), null);
|
||||||
|
|
||||||
if (result.CompletedSynchronously)
|
if (result.CompletedSynchronously)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
|
/// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="appPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
|
||||||
|
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
|
||||||
|
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||||
|
/// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
|
||||||
public DeleteCacheFileTask(
|
public DeleteCacheFileTask(
|
||||||
IApplicationPaths appPaths,
|
IApplicationPaths appPaths,
|
||||||
ILogger<DeleteCacheFileTask> logger,
|
ILogger<DeleteCacheFileTask> logger,
|
||||||
|
|
|
@ -235,12 +235,12 @@ namespace Emby.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void UpdateDeviceName(string sessionId, string deviceName)
|
public void UpdateDeviceName(string sessionId, string reportedDeviceName)
|
||||||
{
|
{
|
||||||
var session = GetSession(sessionId);
|
var session = GetSession(sessionId);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
session.DeviceName = deviceName;
|
session.DeviceName = reportedDeviceName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,14 +316,14 @@ namespace Emby.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnSessionControllerConnected(SessionInfo info)
|
public void OnSessionControllerConnected(SessionInfo session)
|
||||||
{
|
{
|
||||||
EventHelper.QueueEventIfNotNull(
|
EventHelper.QueueEventIfNotNull(
|
||||||
SessionControllerConnected,
|
SessionControllerConnected,
|
||||||
this,
|
this,
|
||||||
new SessionEventArgs
|
new SessionEventArgs
|
||||||
{
|
{
|
||||||
SessionInfo = info
|
SessionInfo = session
|
||||||
},
|
},
|
||||||
_logger);
|
_logger);
|
||||||
}
|
}
|
||||||
|
@ -1581,16 +1581,16 @@ namespace Emby.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task Logout(Device existing)
|
public async Task Logout(Device device)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
_logger.LogInformation("Logging out access token {0}", existing.AccessToken);
|
_logger.LogInformation("Logging out access token {0}", device.AccessToken);
|
||||||
|
|
||||||
await _deviceManager.DeleteDevice(existing).ConfigureAwait(false);
|
await _deviceManager.DeleteDevice(device).ConfigureAwait(false);
|
||||||
|
|
||||||
var sessions = Sessions
|
var sessions = Sessions
|
||||||
.Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
|
.Where(i => string.Equals(i.DeviceId, device.DeviceId, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var session in sessions)
|
foreach (var session in sessions)
|
||||||
|
@ -1601,7 +1601,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError("Error reporting session ended", ex);
|
_logger.LogError(ex, "Error reporting session ended");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ namespace Emby.Server.Implementations.TV
|
||||||
_configurationManager = configurationManager;
|
_configurationManager = configurationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<BaseItem> GetNextUp(NextUpQuery request, DtoOptions dtoOptions)
|
public QueryResult<BaseItem> GetNextUp(NextUpQuery query, DtoOptions options)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(query.UserId);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
@ -43,9 +43,9 @@ namespace Emby.Server.Implementations.TV
|
||||||
}
|
}
|
||||||
|
|
||||||
string presentationUniqueKey = null;
|
string presentationUniqueKey = null;
|
||||||
if (!string.IsNullOrEmpty(request.SeriesId))
|
if (!string.IsNullOrEmpty(query.SeriesId))
|
||||||
{
|
{
|
||||||
if (_libraryManager.GetItemById(request.SeriesId) is Series series)
|
if (_libraryManager.GetItemById(query.SeriesId) is Series series)
|
||||||
{
|
{
|
||||||
presentationUniqueKey = GetUniqueSeriesKey(series);
|
presentationUniqueKey = GetUniqueSeriesKey(series);
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,14 @@ namespace Emby.Server.Implementations.TV
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(presentationUniqueKey))
|
if (!string.IsNullOrEmpty(presentationUniqueKey))
|
||||||
{
|
{
|
||||||
return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, dtoOptions), request);
|
return GetResult(GetNextUpEpisodes(query, user, new[] { presentationUniqueKey }, options), query);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseItem[] parents;
|
BaseItem[] parents;
|
||||||
|
|
||||||
if (request.ParentId.HasValue)
|
if (query.ParentId.HasValue)
|
||||||
{
|
{
|
||||||
var parent = _libraryManager.GetItemById(request.ParentId.Value);
|
var parent = _libraryManager.GetItemById(query.ParentId.Value);
|
||||||
|
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
|
@ -79,10 +79,10 @@ namespace Emby.Server.Implementations.TV
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetNextUp(request, parents, dtoOptions);
|
return GetNextUp(query, parents, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<BaseItem> GetNextUp(NextUpQuery request, BaseItem[] parentsFolders, DtoOptions dtoOptions)
|
public QueryResult<BaseItem> GetNextUp(NextUpQuery request, BaseItem[] parentsFolders, DtoOptions options)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(request.UserId);
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.TV
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(presentationUniqueKey))
|
if (!string.IsNullOrEmpty(presentationUniqueKey))
|
||||||
{
|
{
|
||||||
return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, dtoOptions), request);
|
return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, options), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit.HasValue)
|
if (limit.HasValue)
|
||||||
|
@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.TV
|
||||||
.Select(GetUniqueSeriesKey);
|
.Select(GetUniqueSeriesKey);
|
||||||
|
|
||||||
// Avoid implicitly captured closure
|
// Avoid implicitly captured closure
|
||||||
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
|
var episodes = GetNextUpEpisodes(request, user, items, options);
|
||||||
|
|
||||||
return GetResult(episodes, request);
|
return GetResult(episodes, request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,8 +97,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
|
if (XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) is not LibraryOptions result)
|
||||||
if (result == null)
|
|
||||||
{
|
{
|
||||||
return new LibraryOptions();
|
return new LibraryOptions();
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,13 +104,6 @@ namespace MediaBrowser.Controller
|
||||||
/// <returns>The API URL.</returns>
|
/// <returns>The API URL.</returns>
|
||||||
string GetLocalApiUrl(string hostname, string scheme = null, int? port = null);
|
string GetLocalApiUrl(string hostname, string scheme = null, int? port = null);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Open a URL in an external browser window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url">The URL to open.</param>
|
|
||||||
/// <exception cref="NotSupportedException"><see cref="CanLaunchWebBrowser"/> is false.</exception>
|
|
||||||
void LaunchUrl(string url);
|
|
||||||
|
|
||||||
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
|
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
|
||||||
|
|
||||||
string ExpandVirtualPath(string path);
|
string ExpandVirtualPath(string path);
|
||||||
|
|
|
@ -595,11 +595,11 @@ namespace MediaBrowser.Controller.Library
|
||||||
|
|
||||||
Task RemoveVirtualFolder(string name, bool refreshLibrary);
|
Task RemoveVirtualFolder(string name, bool refreshLibrary);
|
||||||
|
|
||||||
void AddMediaPath(string virtualFolderName, MediaPathInfo path);
|
void AddMediaPath(string virtualFolderName, MediaPathInfo mediaPath);
|
||||||
|
|
||||||
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
|
void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath);
|
||||||
|
|
||||||
void RemoveMediaPath(string virtualFolderName, string path);
|
void RemoveMediaPath(string virtualFolderName, string mediaPath);
|
||||||
|
|
||||||
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <returns>User data dto.</returns>
|
/// <returns>User data dto.</returns>
|
||||||
UserItemDataDto GetUserDataDto(BaseItem item, User user);
|
UserItemDataDto GetUserDataDto(BaseItem item, User user);
|
||||||
|
|
||||||
UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options);
|
UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions options);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all user data for the given user.
|
/// Get all user data for the given user.
|
||||||
|
@ -69,8 +69,8 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">Item to update.</param>
|
/// <param name="item">Item to update.</param>
|
||||||
/// <param name="data">Data to update.</param>
|
/// <param name="data">Data to update.</param>
|
||||||
/// <param name="positionTicks">New playstate.</param>
|
/// <param name="reportedPositionTicks">New playstate.</param>
|
||||||
/// <returns>True if playstate was updated.</returns>
|
/// <returns>True if playstate was updated.</returns>
|
||||||
bool UpdatePlayState(BaseItem item, UserItemData data, long? positionTicks);
|
bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPositionTicks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,7 +274,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
|
|
||||||
Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
|
Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
|
||||||
|
|
||||||
TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
|
TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the lineups.
|
/// Gets the lineups.
|
||||||
|
|
|
@ -70,10 +70,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the timer asynchronous.
|
/// Updates the timer asynchronous.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="info">The information.</param>
|
/// <param name="updatedTimer">The updated timer information.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken);
|
Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the series timer asynchronous.
|
/// Updates the series timer asynchronous.
|
||||||
|
|
|
@ -49,17 +49,17 @@ namespace MediaBrowser.Controller.Persistence
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets chapters for an item.
|
/// Gets chapters for an item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>The list of chapter info.</returns>
|
/// <returns>The list of chapter info.</returns>
|
||||||
List<ChapterInfo> GetChapters(BaseItem id);
|
List<ChapterInfo> GetChapters(BaseItem item);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a single chapter for an item.
|
/// Gets a single chapter for an item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <param name="index">The chapter index.</param>
|
/// <param name="index">The chapter index.</param>
|
||||||
/// <returns>The chapter info at the specified index.</returns>
|
/// <returns>The chapter info at the specified index.</returns>
|
||||||
ChapterInfo GetChapter(BaseItem id, int index);
|
ChapterInfo GetChapter(BaseItem item, int index);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the chapters.
|
/// Saves the chapters.
|
||||||
|
|
|
@ -344,7 +344,7 @@ namespace MediaBrowser.Controller.Session
|
||||||
/// <returns>A <see cref="Task"/> representing the log out process.</returns>
|
/// <returns>A <see cref="Task"/> representing the log out process.</returns>
|
||||||
Task Logout(string accessToken);
|
Task Logout(string accessToken);
|
||||||
|
|
||||||
Task Logout(Device accessToken);
|
Task Logout(Device device);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Revokes the user tokens.
|
/// Revokes the user tokens.
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var stream = TargetAudioStream;
|
var stream = TargetAudioStream;
|
||||||
return AudioSampleRate.HasValue && !IsDirectStream
|
return AudioSampleRate.HasValue && !IsDirectStream
|
||||||
? AudioSampleRate
|
? AudioSampleRate
|
||||||
: stream == null ? null : stream.SampleRate;
|
: stream?.SampleRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
|
return TargetAudioStream?.BitDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetAudioCodecs = TargetAudioCodec;
|
var targetAudioCodecs = TargetAudioCodec;
|
||||||
|
@ -156,7 +156,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetTargetAudioBitDepth(audioCodec);
|
return GetTargetAudioBitDepth(audioCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
|
return TargetAudioStream?.BitDepth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
|
return TargetVideoStream?.BitDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVideoCodecs = TargetVideoCodec;
|
var targetVideoCodecs = TargetVideoCodec;
|
||||||
|
@ -179,7 +179,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetTargetVideoBitDepth(videoCodec);
|
return GetTargetVideoBitDepth(videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
|
return TargetVideoStream?.BitDepth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
|
return TargetVideoStream?.RefFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVideoCodecs = TargetVideoCodec;
|
var targetVideoCodecs = TargetVideoCodec;
|
||||||
|
@ -203,7 +203,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetTargetRefFrames(videoCodec);
|
return GetTargetRefFrames(videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
|
return TargetVideoStream?.RefFrames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
|
return TargetVideoStream?.Level;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVideoCodecs = TargetVideoCodec;
|
var targetVideoCodecs = TargetVideoCodec;
|
||||||
|
@ -240,7 +240,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetTargetVideoLevel(videoCodec);
|
return GetTargetVideoLevel(videoCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
|
return TargetVideoStream?.Level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var stream = TargetVideoStream;
|
var stream = TargetVideoStream;
|
||||||
return !IsDirectStream
|
return !IsDirectStream
|
||||||
? null
|
? null
|
||||||
: stream == null ? null : stream.PacketLength;
|
: stream?.PacketLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? null : TargetVideoStream.Profile;
|
return TargetVideoStream?.Profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVideoCodecs = TargetVideoCodec;
|
var targetVideoCodecs = TargetVideoCodec;
|
||||||
|
@ -277,7 +277,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetOption(videoCodec, "profile");
|
return GetOption(videoCodec, "profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetVideoStream == null ? null : TargetVideoStream.Profile;
|
return TargetVideoStream?.Profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var stream = TargetVideoStream;
|
var stream = TargetVideoStream;
|
||||||
return !IsDirectStream
|
return !IsDirectStream
|
||||||
? null
|
? null
|
||||||
: stream == null ? null : stream.CodecTag;
|
: stream?.CodecTag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
var stream = TargetAudioStream;
|
var stream = TargetAudioStream;
|
||||||
return AudioBitrate.HasValue && !IsDirectStream
|
return AudioBitrate.HasValue && !IsDirectStream
|
||||||
? AudioBitrate
|
? AudioBitrate
|
||||||
: stream == null ? null : stream.BitRate;
|
: stream?.BitRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
|
return TargetAudioStream?.Channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetAudioCodecs = TargetAudioCodec;
|
var targetAudioCodecs = TargetAudioCodec;
|
||||||
|
@ -329,7 +329,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return GetTargetRefFrames(codec);
|
return GetTargetRefFrames(codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
|
return TargetAudioStream?.Channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +425,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
return VideoBitrate.HasValue && !IsDirectStream
|
return VideoBitrate.HasValue && !IsDirectStream
|
||||||
? VideoBitrate
|
? VideoBitrate
|
||||||
: stream == null ? null : stream.BitRate;
|
: stream?.BitRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? null : TargetVideoStream.IsAnamorphic;
|
return TargetVideoStream?.IsAnamorphic;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -464,7 +464,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
|
return TargetVideoStream?.IsInterlaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVideoCodecs = TargetVideoCodec;
|
var targetVideoCodecs = TargetVideoCodec;
|
||||||
|
@ -477,7 +477,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
|
return TargetVideoStream?.IsInterlaced;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +487,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
if (IsDirectStream)
|
if (IsDirectStream)
|
||||||
{
|
{
|
||||||
return TargetVideoStream == null ? null : TargetVideoStream.IsAVC;
|
return TargetVideoStream?.IsAVC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -618,20 +618,20 @@ namespace MediaBrowser.Model.Dlna
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to keep the url clean by omitting defaults
|
// Try to keep the url clean by omitting defaults
|
||||||
if (string.Equals(pair.Name, "StartTimeTicks", StringComparison.OrdinalIgnoreCase) &&
|
if (string.Equals(pair.Name, "StartTimeTicks", StringComparison.OrdinalIgnoreCase)
|
||||||
string.Equals(pair.Value, "0", StringComparison.OrdinalIgnoreCase))
|
&& string.Equals(pair.Value, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(pair.Name, "SubtitleStreamIndex", StringComparison.OrdinalIgnoreCase) &&
|
if (string.Equals(pair.Name, "SubtitleStreamIndex", StringComparison.OrdinalIgnoreCase)
|
||||||
string.Equals(pair.Value, "-1", StringComparison.OrdinalIgnoreCase))
|
&& string.Equals(pair.Value, "-1", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(pair.Name, "Static", StringComparison.OrdinalIgnoreCase) &&
|
if (string.Equals(pair.Name, "Static", StringComparison.OrdinalIgnoreCase)
|
||||||
string.Equals(pair.Value, "false", StringComparison.OrdinalIgnoreCase))
|
&& string.Equals(pair.Value, "false", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -641,7 +641,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
list.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Name, encodedValue));
|
list.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Name, encodedValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
string queryString = string.Join("&", list.ToArray());
|
string queryString = string.Join('&', list);
|
||||||
|
|
||||||
return GetUrl(baseUrl, queryString);
|
return GetUrl(baseUrl, queryString);
|
||||||
}
|
}
|
||||||
|
@ -681,11 +681,11 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
string audioCodecs = item.AudioCodecs.Length == 0 ?
|
string audioCodecs = item.AudioCodecs.Length == 0 ?
|
||||||
string.Empty :
|
string.Empty :
|
||||||
string.Join(",", item.AudioCodecs);
|
string.Join(',', item.AudioCodecs);
|
||||||
|
|
||||||
string videoCodecs = item.VideoCodecs.Length == 0 ?
|
string videoCodecs = item.VideoCodecs.Length == 0 ?
|
||||||
string.Empty :
|
string.Empty :
|
||||||
string.Join(",", item.VideoCodecs);
|
string.Join(',', item.VideoCodecs);
|
||||||
|
|
||||||
list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty));
|
list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty));
|
||||||
list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty));
|
list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty));
|
||||||
|
@ -1024,30 +1024,5 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MediaStream> GetSelectableAudioStreams()
|
|
||||||
{
|
|
||||||
return GetSelectableStreams(MediaStreamType.Audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MediaStream> GetSelectableSubtitleStreams()
|
|
||||||
{
|
|
||||||
return GetSelectableStreams(MediaStreamType.Subtitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MediaStream> GetSelectableStreams(MediaStreamType type)
|
|
||||||
{
|
|
||||||
var list = new List<MediaStream>();
|
|
||||||
|
|
||||||
foreach (var stream in MediaSource.MediaStreams)
|
|
||||||
{
|
|
||||||
if (type == stream.Type)
|
|
||||||
{
|
|
||||||
list.Add(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
<Rule Id="SA1101" Action="None" />
|
<Rule Id="SA1101" Action="None" />
|
||||||
<!-- disable warning SA1108: Block statements should not contain embedded comments -->
|
<!-- disable warning SA1108: Block statements should not contain embedded comments -->
|
||||||
<Rule Id="SA1108" Action="None" />
|
<Rule Id="SA1108" Action="None" />
|
||||||
|
<!-- disable warning SA1118: Parameter must not span multiple lines. -->
|
||||||
|
<Rule Id="SA1118" Action="None" />
|
||||||
<!-- disable warning SA1128:: Put constructor initializers on their own line -->
|
<!-- disable warning SA1128:: Put constructor initializers on their own line -->
|
||||||
<Rule Id="SA1128" Action="None" />
|
<Rule Id="SA1128" Action="None" />
|
||||||
<!-- disable warning SA1130: Use lambda syntax -->
|
<!-- disable warning SA1130: Use lambda syntax -->
|
||||||
|
@ -39,6 +41,10 @@
|
||||||
</Rules>
|
</Rules>
|
||||||
|
|
||||||
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design">
|
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design">
|
||||||
|
<!-- error on CA1305: Specify IFormatProvider -->
|
||||||
|
<Rule Id="CA1305" Action="Error" />
|
||||||
|
<!-- error on CA1725: Parameter names should match base declaration -->
|
||||||
|
<Rule Id="CA1725" Action="Error" />
|
||||||
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
|
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
|
||||||
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
|
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
|
||||||
<Rule Id="CA2016" Action="Error" />
|
<Rule Id="CA2016" Action="Error" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user