commit
afb4a08bfe
|
@ -100,7 +100,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
#if NET46
|
#if NET46
|
||||||
public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
|
public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var options = TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket | TransmitFileOptions.UseKernelApc;
|
var options = TransmitFileOptions.UseKernelApc;
|
||||||
|
|
||||||
var completionSource = new TaskCompletionSource<bool>();
|
var completionSource = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
|
|
@ -97,10 +97,31 @@ namespace Emby.Common.Implementations.Net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ISocket CreateUdpBroadcastSocket(int localPort)
|
||||||
|
{
|
||||||
|
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||||
|
|
||||||
|
var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||||
|
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||||
|
|
||||||
|
return new UdpSocket(retVal, localPort, IPAddress.Any);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (retVal != null)
|
||||||
|
retVal.Dispose();
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
|
/// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
|
/// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
|
||||||
public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
|
public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
|
||||||
{
|
{
|
||||||
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||||
|
|
|
@ -60,6 +60,8 @@ namespace Emby.Common.Implementations.Net
|
||||||
var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
|
var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
|
||||||
state.TaskCompletionSource = tcs;
|
state.TaskCompletionSource = tcs;
|
||||||
|
|
||||||
|
cancellationToken.Register(() => tcs.TrySetCanceled());
|
||||||
|
|
||||||
#if NETSTANDARD1_6
|
#if NETSTANDARD1_6
|
||||||
_Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer), SocketFlags.None, state.RemoteEndPoint)
|
_Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer), SocketFlags.None, state.RemoteEndPoint)
|
||||||
.ContinueWith((task, asyncState) =>
|
.ContinueWith((task, asyncState) =>
|
||||||
|
@ -160,7 +162,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
var bytesRead = receiveData();
|
var bytesRead = receiveData();
|
||||||
|
|
||||||
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
|
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
|
||||||
state.TaskCompletionSource.SetResult(
|
state.TaskCompletionSource.TrySetResult(
|
||||||
new SocketReceiveResult
|
new SocketReceiveResult
|
||||||
{
|
{
|
||||||
Buffer = state.Buffer,
|
Buffer = state.Buffer,
|
||||||
|
@ -172,18 +174,18 @@ namespace Emby.Common.Implementations.Net
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException)
|
catch (ObjectDisposedException)
|
||||||
{
|
{
|
||||||
state.TaskCompletionSource.SetCanceled();
|
state.TaskCompletionSource.TrySetCanceled();
|
||||||
}
|
}
|
||||||
catch (SocketException se)
|
catch (SocketException se)
|
||||||
{
|
{
|
||||||
if (se.SocketErrorCode != SocketError.Interrupted && se.SocketErrorCode != SocketError.OperationAborted && se.SocketErrorCode != SocketError.Shutdown)
|
if (se.SocketErrorCode != SocketError.Interrupted && se.SocketErrorCode != SocketError.OperationAborted && se.SocketErrorCode != SocketError.Shutdown)
|
||||||
state.TaskCompletionSource.SetException(se);
|
state.TaskCompletionSource.TrySetException(se);
|
||||||
else
|
else
|
||||||
state.TaskCompletionSource.SetCanceled();
|
state.TaskCompletionSource.TrySetCanceled();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
state.TaskCompletionSource.SetException(ex);
|
state.TaskCompletionSource.TrySetException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +208,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
var bytesRead = state.Socket.EndReceiveFrom(asyncResult, ref state.RemoteEndPoint);
|
var bytesRead = state.Socket.EndReceiveFrom(asyncResult, ref state.RemoteEndPoint);
|
||||||
|
|
||||||
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
|
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
|
||||||
state.TaskCompletionSource.SetResult(
|
state.TaskCompletionSource.TrySetResult(
|
||||||
new SocketReceiveResult
|
new SocketReceiveResult
|
||||||
{
|
{
|
||||||
Buffer = state.Buffer,
|
Buffer = state.Buffer,
|
||||||
|
@ -218,11 +220,11 @@ namespace Emby.Common.Implementations.Net
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException)
|
catch (ObjectDisposedException)
|
||||||
{
|
{
|
||||||
state.TaskCompletionSource.SetCanceled();
|
state.TaskCompletionSource.TrySetCanceled();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
state.TaskCompletionSource.SetException(ex);
|
state.TaskCompletionSource.TrySetException(ex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ namespace Emby.Drawing
|
||||||
var outputFormat = GetOutputFormat(options.SupportedOutputFormats[0]);
|
var outputFormat = GetOutputFormat(options.SupportedOutputFormats[0]);
|
||||||
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
|
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
|
||||||
|
|
||||||
var imageProcessingLockTaken = false;
|
//var imageProcessingLockTaken = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -253,9 +253,9 @@ namespace Emby.Drawing
|
||||||
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
|
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
|
||||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath));
|
_fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath));
|
||||||
|
|
||||||
await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
|
//await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
imageProcessingLockTaken = true;
|
//imageProcessingLockTaken = true;
|
||||||
|
|
||||||
_imageEncoder.EncodeImage(originalImagePath, tmpPath, AutoOrient(options.Item), newWidth, newHeight, quality, options, outputFormat);
|
_imageEncoder.EncodeImage(originalImagePath, tmpPath, AutoOrient(options.Item), newWidth, newHeight, quality, options, outputFormat);
|
||||||
CopyFile(tmpPath, cacheFilePath);
|
CopyFile(tmpPath, cacheFilePath);
|
||||||
|
@ -273,13 +273,13 @@ namespace Emby.Drawing
|
||||||
// Just spit out the original file if all the options are default
|
// Just spit out the original file if all the options are default
|
||||||
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
|
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
|
||||||
}
|
}
|
||||||
finally
|
//finally
|
||||||
{
|
//{
|
||||||
if (imageProcessingLockTaken)
|
// if (imageProcessingLockTaken)
|
||||||
{
|
// {
|
||||||
_imageProcessingSemaphore.Release();
|
// _imageProcessingSemaphore.Release();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyFile(string src, string destination)
|
private void CopyFile(string src, string destination)
|
||||||
|
|
|
@ -9,6 +9,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
@ -22,13 +23,15 @@ namespace Emby.Server.Implementations.Data
|
||||||
private readonly IItemRepository _itemRepo;
|
private readonly IItemRepository _itemRepo;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IFileSystem fileSystem)
|
public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_itemRepo = itemRepo;
|
_itemRepo = itemRepo;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_appPaths = appPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
@ -150,13 +153,27 @@ namespace Emby.Server.Implementations.Data
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_fileSystem.FileExists(path) || _fileSystem.DirectoryExists(path))
|
var isPathInLibrary = false;
|
||||||
|
|
||||||
|
if (allLibraryPaths.Any(i => path.StartsWith(i, StringComparison.Ordinal)) ||
|
||||||
|
allLibraryPaths.Contains(path, StringComparer.Ordinal) ||
|
||||||
|
path.StartsWith(_appPaths.ProgramDataPath, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
continue;
|
isPathInLibrary = true;
|
||||||
|
|
||||||
|
if (_fileSystem.FileExists(path) || _fileSystem.DirectoryExists(path))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var libraryItem = _libraryManager.GetItemById(item.Item1);
|
var libraryItem = _libraryManager.GetItemById(item.Item1);
|
||||||
|
|
||||||
|
if (libraryItem == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (libraryItem.IsTopParent)
|
if (libraryItem.IsTopParent)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -180,7 +197,14 @@ namespace Emby.Server.Implementations.Data
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Info("Deleting item from database {0} because path no longer exists. type: {1} path: {2}", libraryItem.Name, libraryItem.GetType().Name, libraryItemPath ?? string.Empty);
|
if (isPathInLibrary)
|
||||||
|
{
|
||||||
|
_logger.Info("Deleting item from database {0} because path no longer exists. type: {1} path: {2}", libraryItem.Name, libraryItem.GetType().Name, libraryItemPath ?? string.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Deleting item from database {0} because path is no longer in the server library. type: {1} path: {2}", libraryItem.Name, libraryItem.GetType().Name, libraryItemPath ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
await libraryItem.OnFileDeleted().ConfigureAwait(false);
|
await libraryItem.OnFileDeleted().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,6 @@
|
||||||
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
|
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
|
||||||
<Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" />
|
<Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" />
|
||||||
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" />
|
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" />
|
||||||
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunDiscovery.cs" />
|
|
||||||
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
|
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
|
||||||
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
|
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
|
||||||
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
|
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
public List<Cookie> Cookies { get; private set; }
|
public List<Cookie> Cookies { get; private set; }
|
||||||
|
|
||||||
|
public FileShareMode FileShare { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _options
|
/// The _options
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -69,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
SetRangeValues();
|
SetRangeValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileShare = FileShareMode.Read;
|
||||||
Cookies = new List<Cookie>();
|
Cookies = new List<Cookie>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +156,11 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
|
if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
|
||||||
{
|
{
|
||||||
Logger.Info("Transmit file {0}", Path);
|
Logger.Info("Transmit file {0}", Path);
|
||||||
await response.TransmitFile(Path, 0, 0, cancellationToken).ConfigureAwait(false);
|
await response.TransmitFile(Path, 0, 0, FileShare, cancellationToken).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await response.TransmitFile(Path, RangeStart, RangeEnd, cancellationToken).ConfigureAwait(false);
|
await response.TransmitFile(Path, RangeStart, RangeEnd, FileShare, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -556,12 +556,13 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
{
|
{
|
||||||
var rangeHeader = requestContext.Headers.Get("Range");
|
var rangeHeader = requestContext.Headers.Get("Range");
|
||||||
|
|
||||||
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path) && options.FileShare == FileShareMode.Read)
|
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
|
||||||
{
|
{
|
||||||
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
||||||
{
|
{
|
||||||
OnComplete = options.OnComplete,
|
OnComplete = options.OnComplete,
|
||||||
OnError = options.OnError
|
OnError = options.OnError,
|
||||||
|
FileShare = options.FileShare
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,9 +193,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
|
public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return _response.TransmitFile(path, offset, count, cancellationToken);
|
return _response.TransmitFile(path, offset, count, fileShareMode, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,6 +513,11 @@ namespace Emby.Server.Implementations.Library
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid GetNewItemId(string key, Type type)
|
public Guid GetNewItemId(string key, Type type)
|
||||||
|
{
|
||||||
|
return GetNewItemIdInternal(key, type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid GetNewItemIdInternal(string key, Type type, bool forceCaseInsensitive)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(key))
|
if (string.IsNullOrWhiteSpace(key))
|
||||||
{
|
{
|
||||||
|
@ -531,7 +536,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
.Replace("/", "\\");
|
.Replace("/", "\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
|
if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
|
||||||
{
|
{
|
||||||
key = key.ToLower();
|
key = key.ToLower();
|
||||||
}
|
}
|
||||||
|
@ -865,7 +870,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{Person}.</returns>
|
/// <returns>Task{Person}.</returns>
|
||||||
public Person GetPerson(string name)
|
public Person GetPerson(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<Person>(Person.GetPath(name), name);
|
return CreateItemByName<Person>(Person.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -875,7 +880,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{Studio}.</returns>
|
/// <returns>Task{Studio}.</returns>
|
||||||
public Studio GetStudio(string name)
|
public Studio GetStudio(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<Studio>(Studio.GetPath(name), name);
|
return CreateItemByName<Studio>(Studio.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -885,7 +890,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{Genre}.</returns>
|
/// <returns>Task{Genre}.</returns>
|
||||||
public Genre GetGenre(string name)
|
public Genre GetGenre(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<Genre>(Genre.GetPath(name), name);
|
return CreateItemByName<Genre>(Genre.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -895,7 +900,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{MusicGenre}.</returns>
|
/// <returns>Task{MusicGenre}.</returns>
|
||||||
public MusicGenre GetMusicGenre(string name)
|
public MusicGenre GetMusicGenre(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<MusicGenre>(MusicGenre.GetPath(name), name);
|
return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -905,7 +910,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{GameGenre}.</returns>
|
/// <returns>Task{GameGenre}.</returns>
|
||||||
public GameGenre GetGameGenre(string name)
|
public GameGenre GetGameGenre(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<GameGenre>(GameGenre.GetPath(name), name);
|
return CreateItemByName<GameGenre>(GameGenre.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -923,7 +928,7 @@ namespace Emby.Server.Implementations.Library
|
||||||
|
|
||||||
var name = value.ToString(CultureInfo.InvariantCulture);
|
var name = value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
return CreateItemByName<Year>(Year.GetPath(name), name);
|
return CreateItemByName<Year>(Year.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -933,10 +938,10 @@ namespace Emby.Server.Implementations.Library
|
||||||
/// <returns>Task{Genre}.</returns>
|
/// <returns>Task{Genre}.</returns>
|
||||||
public MusicArtist GetArtist(string name)
|
public MusicArtist GetArtist(string name)
|
||||||
{
|
{
|
||||||
return CreateItemByName<MusicArtist>(MusicArtist.GetPath(name), name);
|
return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private T CreateItemByName<T>(string path, string name)
|
private T CreateItemByName<T>(Func<string,string> getPathFn, string name)
|
||||||
where T : BaseItem, new()
|
where T : BaseItem, new()
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(MusicArtist))
|
if (typeof(T) == typeof(MusicArtist))
|
||||||
|
@ -957,7 +962,9 @@ namespace Emby.Server.Implementations.Library
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = GetNewItemId(path, typeof(T));
|
var path = getPathFn(name);
|
||||||
|
var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
|
||||||
|
var id = GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
|
||||||
|
|
||||||
var item = GetItemById(id) as T;
|
var item = GetItemById(id) as T;
|
||||||
|
|
||||||
|
|
|
@ -2542,6 +2542,60 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
public ProgramInfo Program { get; set; }
|
public ProgramInfo Program { get; set; }
|
||||||
public CancellationTokenSource CancellationTokenSource { get; set; }
|
public CancellationTokenSource CancellationTokenSource { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ScanForTunerDeviceChanges(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
foreach (var host in _liveTvManager.TunerHosts)
|
||||||
|
{
|
||||||
|
await ScanForTunerDeviceChanges(host, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ScanForTunerDeviceChanges(ITunerHost host, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var discoveredDevices = await DiscoverDevices(host, 3000, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var configuredDevices = GetConfiguration().TunerHosts
|
||||||
|
.Where(i => string.Equals(i.Type, host.Type, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var device in discoveredDevices)
|
||||||
|
{
|
||||||
|
var configuredDevice = configuredDevices.FirstOrDefault(i => string.Equals(i.DeviceId, device.DeviceId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (configuredDevice != null)
|
||||||
|
{
|
||||||
|
if (!string.Equals(device.Url, configuredDevice.Url, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.Info("Tuner url has changed from {0} to {1}", configuredDevice.Url, device.Url);
|
||||||
|
|
||||||
|
configuredDevice.Url = device.Url;
|
||||||
|
await _liveTvManager.SaveTunerHost(configuredDevice).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<TunerHostInfo>> DiscoverDevices(ITunerHost host, int discoveryDuationMs, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var discoveredDevices = await host.DiscoverDevices(discoveryDuationMs, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (var device in discoveredDevices)
|
||||||
|
{
|
||||||
|
_logger.Info("Discovered tuner device {0} at {1}", host.Name, device.Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return discoveredDevices;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error discovering tuner devices", ex);
|
||||||
|
|
||||||
|
return new List<TunerHostInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static class ConfigurationExtension
|
public static class ConfigurationExtension
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,6 +150,16 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
get { return _listingProviders; }
|
get { return _listingProviders; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<NameIdPair> GetTunerHostTypes()
|
||||||
|
{
|
||||||
|
return _tunerHosts.OrderBy(i => i.Name).Select(i => new NameIdPair
|
||||||
|
{
|
||||||
|
Name = i.Name,
|
||||||
|
Id = i.Type
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
void service_DataSourceChanged(object sender, EventArgs e)
|
void service_DataSourceChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
|
@ -1180,6 +1190,8 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
{
|
{
|
||||||
EmbyTV.EmbyTV.Current.CreateRecordingFolders();
|
EmbyTV.EmbyTV.Current.CreateRecordingFolders();
|
||||||
|
|
||||||
|
await EmbyTV.EmbyTV.Current.ScanForTunerDeviceChanges(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
double progressPerService = _services.Count == 0
|
double progressPerService = _services.Count == 0
|
||||||
? 0
|
? 0
|
||||||
|
@ -2748,7 +2760,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
private bool IsLiveTvEnabled(User user)
|
private bool IsLiveTvEnabled(User user)
|
||||||
{
|
{
|
||||||
return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count(i => i.IsEnabled) > 0);
|
return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<User> GetEnabledUsers()
|
public IEnumerable<User> GetEnabledUsers()
|
||||||
|
@ -2986,7 +2998,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var config = GetConfiguration();
|
var config = GetConfiguration();
|
||||||
if (config.TunerHosts.Count(i => i.IsEnabled) > 0 &&
|
if (config.TunerHosts.Count > 0 &&
|
||||||
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
|
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new MBRegistrationRecord
|
return Task.FromResult(new MBRegistrationRecord
|
||||||
|
@ -3000,50 +3012,6 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
return _security.GetRegistrationStatus(feature);
|
return _security.GetRegistrationStatus(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<NameValuePair> GetSatIniMappings()
|
|
||||||
{
|
|
||||||
return new List<NameValuePair>();
|
|
||||||
//var names = GetType().Assembly.GetManifestResourceNames().Where(i => i.IndexOf("SatIp.ini", StringComparison.OrdinalIgnoreCase) != -1).ToList();
|
|
||||||
|
|
||||||
//return names.Select(GetSatIniMappings).Where(i => i != null).DistinctBy(i => i.Value.Split('|')[0]).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NameValuePair GetSatIniMappings(string resource)
|
|
||||||
{
|
|
||||||
return new NameValuePair();
|
|
||||||
//using (var stream = GetType().Assembly.GetManifestResourceStream(resource))
|
|
||||||
//{
|
|
||||||
// using (var reader = new StreamReader(stream))
|
|
||||||
// {
|
|
||||||
// var parser = new StreamIniDataParser();
|
|
||||||
// IniData data = parser.ReadData(reader);
|
|
||||||
|
|
||||||
// var satType1 = data["SATTYPE"]["1"];
|
|
||||||
// var satType2 = data["SATTYPE"]["2"];
|
|
||||||
|
|
||||||
// if (string.IsNullOrWhiteSpace(satType2))
|
|
||||||
// {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var srch = "SatIp.ini.";
|
|
||||||
// var filename = Path.GetFileName(resource);
|
|
||||||
|
|
||||||
// return new NameValuePair
|
|
||||||
// {
|
|
||||||
// Name = satType1 + " " + satType2,
|
|
||||||
// Value = satType2 + "|" + filename.Substring(filename.IndexOf(srch) + srch.Length)
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.FromResult(new List<ChannelInfo>());
|
|
||||||
//return new TunerHosts.SatIp.ChannelScan(_logger).Scan(info, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken)
|
public Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
|
var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
|
|
||||||
public bool IsHidden
|
public bool IsHidden
|
||||||
{
|
{
|
||||||
get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count(i => i.IsEnabled) == 0; }
|
get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
protected virtual List<TunerHostInfo> GetTunerHosts()
|
protected virtual List<TunerHostInfo> GetTunerHosts()
|
||||||
{
|
{
|
||||||
return GetConfiguration().TunerHosts
|
return GetConfiguration().TunerHosts
|
||||||
.Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
|
.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.Plugins;
|
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.LiveTv;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
using MediaBrowser.Model.Events;
|
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|
||||||
{
|
|
||||||
public class HdHomerunDiscovery : IServerEntryPoint
|
|
||||||
{
|
|
||||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
|
||||||
private readonly IServerConfigurationManager _config;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
|
||||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
|
||||||
private readonly IHttpClient _httpClient;
|
|
||||||
private readonly IJsonSerializer _json;
|
|
||||||
|
|
||||||
public HdHomerunDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient, IJsonSerializer json)
|
|
||||||
{
|
|
||||||
_deviceDiscovery = deviceDiscovery;
|
|
||||||
_config = config;
|
|
||||||
_logger = logger;
|
|
||||||
_liveTvManager = liveTvManager;
|
|
||||||
_httpClient = httpClient;
|
|
||||||
_json = json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Run()
|
|
||||||
{
|
|
||||||
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
|
|
||||||
{
|
|
||||||
string server = null;
|
|
||||||
var info = e.Argument;
|
|
||||||
|
|
||||||
if (info.Headers.TryGetValue("SERVER", out server) && server.IndexOf("HDHomeRun", StringComparison.OrdinalIgnoreCase) != -1)
|
|
||||||
{
|
|
||||||
string location;
|
|
||||||
if (info.Headers.TryGetValue("Location", out location))
|
|
||||||
{
|
|
||||||
//_logger.Debug("HdHomerun found at {0}", location);
|
|
||||||
|
|
||||||
// Just get the beginning of the url
|
|
||||||
Uri uri;
|
|
||||||
if (Uri.TryCreate(location, UriKind.Absolute, out uri))
|
|
||||||
{
|
|
||||||
var apiUrl = location.Replace(uri.LocalPath, String.Empty, StringComparison.OrdinalIgnoreCase)
|
|
||||||
.TrimEnd('/');
|
|
||||||
|
|
||||||
//_logger.Debug("HdHomerun api url: {0}", apiUrl);
|
|
||||||
AddDevice(apiUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void AddDevice(string url)
|
|
||||||
{
|
|
||||||
await _semaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var options = GetConfiguration();
|
|
||||||
|
|
||||||
if (options.TunerHosts.Any(i =>
|
|
||||||
string.Equals(i.Type, HdHomerunHost.DeviceType, StringComparison.OrdinalIgnoreCase) &&
|
|
||||||
UriEquals(i.Url, url)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip off the port
|
|
||||||
url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/');
|
|
||||||
|
|
||||||
// Test it by pulling down the lineup
|
|
||||||
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
|
||||||
{
|
|
||||||
Url = string.Format("{0}/discover.json", url),
|
|
||||||
CancellationToken = CancellationToken.None,
|
|
||||||
BufferContent = false
|
|
||||||
}))
|
|
||||||
{
|
|
||||||
var response = _json.DeserializeFromStream<HdHomerunHost.DiscoverResponse>(stream);
|
|
||||||
|
|
||||||
var existing = GetConfiguration().TunerHosts
|
|
||||||
.FirstOrDefault(i => string.Equals(i.Type, HdHomerunHost.DeviceType, StringComparison.OrdinalIgnoreCase) && string.Equals(i.DeviceId, response.DeviceID, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
if (existing == null)
|
|
||||||
{
|
|
||||||
await _liveTvManager.SaveTunerHost(new TunerHostInfo
|
|
||||||
{
|
|
||||||
Type = HdHomerunHost.DeviceType,
|
|
||||||
Url = url,
|
|
||||||
DeviceId = response.DeviceID
|
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!string.Equals(existing.Url, url, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
existing.Url = url;
|
|
||||||
await _liveTvManager.SaveTunerHost(existing).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error saving device", ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool UriEquals(string savedUri, string location)
|
|
||||||
{
|
|
||||||
return string.Equals(NormalizeUrl(location), NormalizeUrl(savedUri), StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string NormalizeUrl(string url)
|
|
||||||
{
|
|
||||||
if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
url = "http://" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
url = url.TrimEnd('/');
|
|
||||||
|
|
||||||
// Strip off the port
|
|
||||||
return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LiveTvOptions GetConfiguration()
|
|
||||||
{
|
|
||||||
return _config.GetConfiguration<LiveTvOptions>("livetv");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
var list = new List<LiveTvTunerInfo>();
|
var list = new List<LiveTvTunerInfo>();
|
||||||
|
|
||||||
foreach (var host in GetConfiguration().TunerHosts
|
foreach (var host in GetConfiguration().TunerHosts
|
||||||
.Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)))
|
.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -587,7 +587,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
|
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
|
||||||
|
|
||||||
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
|
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
|
||||||
{
|
{
|
||||||
var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
|
var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
|
||||||
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -605,11 +605,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
public async Task Validate(TunerHostInfo info)
|
public async Task Validate(TunerHostInfo info)
|
||||||
{
|
{
|
||||||
if (!info.IsEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_modelCache)
|
lock (_modelCache)
|
||||||
{
|
{
|
||||||
_modelCache.Clear();
|
_modelCache.Clear();
|
||||||
|
@ -652,5 +647,74 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
public string LineupURL { get; set; }
|
public string LineupURL { get; set; }
|
||||||
public int TunerCount { get; set; }
|
public int TunerCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(discoveryDurationMs).Token, cancellationToken).Token;
|
||||||
|
var list = new List<TunerHostInfo>();
|
||||||
|
|
||||||
|
// Create udp broadcast discovery message
|
||||||
|
byte[] discBytes = { 0, 2, 0, 12, 1, 4, 255, 255, 255, 255, 2, 4, 255, 255, 255, 255, 115, 204, 125, 143 };
|
||||||
|
using (var udpClient = _socketFactory.CreateUdpBroadcastSocket(0))
|
||||||
|
{
|
||||||
|
// Need a way to set the Receive timeout on the socket otherwise this might never timeout?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await udpClient.SendAsync(discBytes, discBytes.Length, new IpEndPointInfo(new IpAddressInfo("255.255.255.255", IpAddressFamily.InterNetwork), 65001), cancellationToken);
|
||||||
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
var response = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
var deviceIp = response.RemoteEndPoint.IpAddress.Address;
|
||||||
|
|
||||||
|
// check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte
|
||||||
|
if (response.ReceivedBytes > 13 && response.Buffer[1] == 3)
|
||||||
|
{
|
||||||
|
var deviceAddress = "http://" + deviceIp;
|
||||||
|
|
||||||
|
var info = await TryGetTunerHostInfo(deviceAddress, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
list.Add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Socket timeout indicates all messages have been received.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TunerHostInfo> TryGetTunerHostInfo(string url, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var hostInfo = new TunerHostInfo
|
||||||
|
{
|
||||||
|
Type = Type,
|
||||||
|
Url = url
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var modelInfo = await GetModelInfo(hostInfo, false, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
hostInfo.DeviceId = modelInfo.DeviceID;
|
||||||
|
|
||||||
|
return hostInfo;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// logged at lower levels
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,5 +176,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.FromResult(new List<TunerHostInfo>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -582,13 +582,13 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ListingProviders/Default", "GET")]
|
[Route("/LiveTv/ListingProviders/Default", "GET")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
|
public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
|
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
|
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
|
||||||
{
|
{
|
||||||
public bool ValidateLogin { get; set; }
|
public bool ValidateLogin { get; set; }
|
||||||
|
@ -596,7 +596,7 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
|
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class DeleteListingProvider : IReturnVoid
|
public class DeleteListingProvider : IReturnVoid
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
|
||||||
|
@ -604,7 +604,7 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
|
[Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class GetLineups : IReturn<List<NameIdPair>>
|
public class GetLineups : IReturn<List<NameIdPair>>
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
@ -621,13 +621,13 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ListingProviders/SchedulesDirect/Countries", "GET", Summary = "Gets available lineups")]
|
[Route("/LiveTv/ListingProviders/SchedulesDirect/Countries", "GET", Summary = "Gets available lineups")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class GetSchedulesDirectCountries
|
public class GetSchedulesDirectCountries
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ChannelMappingOptions")]
|
[Route("/LiveTv/ChannelMappingOptions")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class GetChannelMappingOptions
|
public class GetChannelMappingOptions
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
@ -635,7 +635,7 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/ChannelMappings")]
|
[Route("/LiveTv/ChannelMappings")]
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
[Authenticated]
|
||||||
public class SetChannelMapping
|
public class SetChannelMapping
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
@ -660,20 +660,6 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
public string Feature { get; set; }
|
public string Feature { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/LiveTv/TunerHosts/Satip/IniMappings", "GET", Summary = "Gets available mappings")]
|
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
|
||||||
public class GetSatIniMappings : IReturn<List<NameValuePair>>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("/LiveTv/TunerHosts/Satip/ChannelScan", "GET", Summary = "Scans for available channels")]
|
|
||||||
[Authenticated(AllowBeforeStartupWizard = true)]
|
|
||||||
public class GetSatChannnelScanResult : TunerHostInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("/LiveTv/LiveStreamFiles/{Id}/stream.{Container}", "GET", Summary = "Gets a live tv channel")]
|
[Route("/LiveTv/LiveStreamFiles/{Id}/stream.{Container}", "GET", Summary = "Gets a live tv channel")]
|
||||||
public class GetLiveStreamFile
|
public class GetLiveStreamFile
|
||||||
{
|
{
|
||||||
|
@ -687,6 +673,13 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("/LiveTv/TunerHosts/Types", "GET")]
|
||||||
|
[Authenticated]
|
||||||
|
public class GetTunerHostTypes : IReturn<List<NameIdPair>>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public class LiveTvService : BaseApiService
|
public class LiveTvService : BaseApiService
|
||||||
{
|
{
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
private readonly ILiveTvManager _liveTvManager;
|
||||||
|
@ -712,6 +705,12 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
_sessionContext = sessionContext;
|
_sessionContext = sessionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetTunerHostTypes request)
|
||||||
|
{
|
||||||
|
var list = _liveTvManager.GetTunerHostTypes();
|
||||||
|
return ToOptimizedResult(list);
|
||||||
|
}
|
||||||
|
|
||||||
public object Get(GetLiveRecordingFile request)
|
public object Get(GetLiveRecordingFile request)
|
||||||
{
|
{
|
||||||
var path = _liveTvManager.GetEmbyTvActiveRecordingPath(request.Id);
|
var path = _liveTvManager.GetEmbyTvActiveRecordingPath(request.Id);
|
||||||
|
@ -749,13 +748,6 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
return ToOptimizedResult(new ListingsProviderInfo());
|
return ToOptimizedResult(new ListingsProviderInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<object> Get(GetSatChannnelScanResult request)
|
|
||||||
{
|
|
||||||
var result = await _liveTvManager.GetSatChannelScanResult(request, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
||||||
{
|
{
|
||||||
var result = await _liveTvManager.GetRegistrationInfo(request.Feature).ConfigureAwait(false);
|
var result = await _liveTvManager.GetRegistrationInfo(request.Feature).ConfigureAwait(false);
|
||||||
|
@ -803,11 +795,6 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetSatIniMappings request)
|
|
||||||
{
|
|
||||||
return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<object> Get(GetSchedulesDirectCountries request)
|
public async Task<object> Get(GetSchedulesDirectCountries request)
|
||||||
{
|
{
|
||||||
// https://json.schedulesdirect.org/20141201/available/countries
|
// https://json.schedulesdirect.org/20141201/available/countries
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Connect;
|
using MediaBrowser.Controller.Connect;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.LiveTv;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -52,16 +49,14 @@ namespace MediaBrowser.Api
|
||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IConnectManager _connectManager;
|
private readonly IConnectManager _connectManager;
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
|
||||||
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager, IMediaEncoder mediaEncoder)
|
public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, IMediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_connectManager = connectManager;
|
_connectManager = connectManager;
|
||||||
_liveTvManager = liveTvManager;
|
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,20 +87,6 @@ namespace MediaBrowser.Api
|
||||||
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
|
PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage
|
||||||
};
|
};
|
||||||
|
|
||||||
var tvConfig = GetLiveTVConfiguration();
|
|
||||||
|
|
||||||
if (tvConfig.TunerHosts.Count > 0)
|
|
||||||
{
|
|
||||||
result.LiveTvTunerPath = tvConfig.TunerHosts[0].Url;
|
|
||||||
result.LiveTvTunerType = tvConfig.TunerHosts[0].Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tvConfig.ListingProviders.Count > 0)
|
|
||||||
{
|
|
||||||
result.LiveTvGuideProviderId = tvConfig.ListingProviders[0].Id;
|
|
||||||
result.LiveTvGuideProviderType = tvConfig.ListingProviders[0].Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +101,7 @@ namespace MediaBrowser.Api
|
||||||
config.EnableSeriesPresentationUniqueKey = true;
|
config.EnableSeriesPresentationUniqueKey = true;
|
||||||
config.EnableLocalizedGuids = true;
|
config.EnableLocalizedGuids = true;
|
||||||
config.EnableSimpleArtistDetection = true;
|
config.EnableSimpleArtistDetection = true;
|
||||||
|
config.EnableNormalizedItemByNameIds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Post(UpdateStartupConfiguration request)
|
public void Post(UpdateStartupConfiguration request)
|
||||||
|
@ -128,9 +110,6 @@ namespace MediaBrowser.Api
|
||||||
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
|
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
|
||||||
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
|
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
|
||||||
_config.SaveConfiguration();
|
_config.SaveConfiguration();
|
||||||
|
|
||||||
var task = UpdateTuners(request);
|
|
||||||
Task.WaitAll(task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetStartupUser request)
|
public object Get(GetStartupUser request)
|
||||||
|
@ -165,51 +144,6 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTuners(UpdateStartupConfiguration request)
|
|
||||||
{
|
|
||||||
var config = GetLiveTVConfiguration();
|
|
||||||
var save = false;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(request.LiveTvTunerPath) ||
|
|
||||||
string.IsNullOrWhiteSpace(request.LiveTvTunerType))
|
|
||||||
{
|
|
||||||
if (config.TunerHosts.Count > 0)
|
|
||||||
{
|
|
||||||
config.TunerHosts.Clear();
|
|
||||||
save = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!config.TunerHosts.Any(i => string.Equals(i.Type, request.LiveTvTunerType, StringComparison.OrdinalIgnoreCase) && string.Equals(i.Url, request.LiveTvTunerPath, StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
// Add tuner
|
|
||||||
await _liveTvManager.SaveTunerHost(new TunerHostInfo
|
|
||||||
{
|
|
||||||
IsEnabled = true,
|
|
||||||
Type = request.LiveTvTunerType,
|
|
||||||
Url = request.LiveTvTunerPath
|
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (save)
|
|
||||||
{
|
|
||||||
SaveLiveTVConfiguration(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveLiveTVConfiguration(LiveTvOptions config)
|
|
||||||
{
|
|
||||||
_config.SaveConfiguration("livetv", config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LiveTvOptions GetLiveTVConfiguration()
|
|
||||||
{
|
|
||||||
return _config.GetConfiguration<LiveTvOptions>("livetv");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StartupConfiguration
|
public class StartupConfiguration
|
||||||
|
@ -217,10 +151,6 @@ namespace MediaBrowser.Api
|
||||||
public string UICulture { get; set; }
|
public string UICulture { get; set; }
|
||||||
public string MetadataCountryCode { get; set; }
|
public string MetadataCountryCode { get; set; }
|
||||||
public string PreferredMetadataLanguage { get; set; }
|
public string PreferredMetadataLanguage { get; set; }
|
||||||
public string LiveTvTunerType { get; set; }
|
|
||||||
public string LiveTvTunerPath { get; set; }
|
|
||||||
public string LiveTvGuideProviderId { get; set; }
|
|
||||||
public string LiveTvGuideProviderType { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StartupInfo
|
public class StartupInfo
|
||||||
|
|
|
@ -289,7 +289,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -118,7 +118,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
return LibraryManager.GetItemList(query);
|
return LibraryManager.GetItemList(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -96,7 +96,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -108,7 +108,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -133,7 +133,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validFilename = normalizeName ?
|
var validFilename = normalizeName ?
|
||||||
|
|
|
@ -114,7 +114,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -122,7 +122,12 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPath(string name, bool normalizeName = true)
|
public static string GetPath(string name)
|
||||||
|
{
|
||||||
|
return GetPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string name, bool normalizeName)
|
||||||
{
|
{
|
||||||
// Trim the period at the end because windows will have a hard time with that
|
// Trim the period at the end because windows will have a hard time with that
|
||||||
var validName = normalizeName ?
|
var validName = normalizeName ?
|
||||||
|
|
|
@ -376,19 +376,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task OnRecordingFileDeleted(BaseItem recording);
|
Task OnRecordingFileDeleted(BaseItem recording);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the sat ini mappings.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>List<NameValuePair>.</returns>
|
|
||||||
List<NameValuePair> GetSatIniMappings();
|
|
||||||
|
|
||||||
Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
|
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
|
||||||
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
|
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
List<IListingsProvider> ListingProviders { get; }
|
List<IListingsProvider> ListingProviders { get; }
|
||||||
|
|
||||||
|
List<NameIdPair> GetTunerHostTypes();
|
||||||
|
|
||||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
||||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
|
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
|
||||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
||||||
|
|
|
@ -44,6 +44,8 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
/// <returns>Task<List<MediaSourceInfo>>.</returns>
|
||||||
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
public interface IConfigurableTunerHost
|
public interface IConfigurableTunerHost
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public bool EnableHttps { get; set; }
|
public bool EnableHttps { get; set; }
|
||||||
public bool EnableSeriesPresentationUniqueKey { get; set; }
|
public bool EnableSeriesPresentationUniqueKey { get; set; }
|
||||||
public bool EnableLocalizedGuids { get; set; }
|
public bool EnableLocalizedGuids { get; set; }
|
||||||
|
public bool EnableNormalizedItemByNameIds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
|
/// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
|
||||||
|
|
|
@ -46,14 +46,13 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
public string DeviceId { get; set; }
|
public string DeviceId { get; set; }
|
||||||
|
public string FriendlyName { get; set; }
|
||||||
public bool ImportFavoritesOnly { get; set; }
|
public bool ImportFavoritesOnly { get; set; }
|
||||||
public bool AllowHWTranscoding { get; set; }
|
public bool AllowHWTranscoding { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
|
||||||
public bool EnableTvgId { get; set; }
|
public bool EnableTvgId { get; set; }
|
||||||
|
|
||||||
public TunerHostInfo()
|
public TunerHostInfo()
|
||||||
{
|
{
|
||||||
IsEnabled = true;
|
|
||||||
AllowHWTranscoding = true;
|
AllowHWTranscoding = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace MediaBrowser.Model.Net
|
||||||
/// <returns>A <see cref="ISocket"/> implementation.</returns>
|
/// <returns>A <see cref="ISocket"/> implementation.</returns>
|
||||||
ISocket CreateUdpSocket(int localPort);
|
ISocket CreateUdpSocket(int localPort);
|
||||||
|
|
||||||
|
ISocket CreateUdpBroadcastSocket(int localPort);
|
||||||
|
|
||||||
ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
|
ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Services
|
namespace MediaBrowser.Model.Services
|
||||||
{
|
{
|
||||||
|
@ -154,6 +155,6 @@ namespace MediaBrowser.Model.Services
|
||||||
//Add Metadata to Response
|
//Add Metadata to Response
|
||||||
Dictionary<string, object> Items { get; }
|
Dictionary<string, object> Items { get; }
|
||||||
|
|
||||||
Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken);
|
Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("3.2.7.3")]
|
[assembly: AssemblyVersion("3.2.7.4")]
|
||||||
|
|
|
@ -515,9 +515,9 @@ namespace SocketHttpListener.Net
|
||||||
cookies.Add(cookie);
|
cookies.Add(cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
|
public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, cancellationToken);
|
return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -307,13 +307,13 @@ namespace SocketHttpListener.Net
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
|
public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked)
|
//if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked)
|
||||||
//{
|
//{
|
||||||
// return TransmitFileOverSocket(path, offset, count, cancellationToken);
|
// return TransmitFileOverSocket(path, offset, count, cancellationToken);
|
||||||
//}
|
//}
|
||||||
return TransmitFileManaged(path, offset, count, cancellationToken);
|
return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly byte[] _emptyBuffer = new byte[] { };
|
private readonly byte[] _emptyBuffer = new byte[] { };
|
||||||
|
@ -334,7 +334,7 @@ namespace SocketHttpListener.Net
|
||||||
await _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken).ConfigureAwait(false);
|
await _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TransmitFileManaged(string path, long offset, long count, CancellationToken cancellationToken)
|
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var chunked = response.SendChunked;
|
var chunked = response.SendChunked;
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ namespace SocketHttpListener.Net
|
||||||
await WriteAsync(_emptyBuffer, 0, 0, cancellationToken).ConfigureAwait(false);
|
await WriteAsync(_emptyBuffer, 0, 0, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true))
|
using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true))
|
||||||
{
|
{
|
||||||
if (offset > 0)
|
if (offset > 0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user