aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Common.Implementations/Net/NetAcceptSocket.cs2
-rw-r--r--Emby.Common.Implementations/Net/SocketFactory.cs27
-rw-r--r--Emby.Common.Implementations/Net/UdpSocket.cs18
-rw-r--r--Emby.Drawing/ImageProcessor.cs20
-rw-r--r--Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs32
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj1
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs7
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs5
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs4
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs27
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs54
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs60
-rw-r--r--Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs158
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs78
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs5
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs53
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs76
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs7
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs7
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs10
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs2
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs3
-rw-r--r--MediaBrowser.Model/Net/ISocketFactory.cs2
-rw-r--r--MediaBrowser.Model/Services/IRequest.cs3
-rw-r--r--SharedVersion.cs2
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerResponse.cs4
-rw-r--r--SocketHttpListener.Portable/Net/ResponseStream.cs8
35 files changed, 328 insertions, 387 deletions
diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs
index e21ffe553..3721709e6 100644
--- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs
+++ b/Emby.Common.Implementations/Net/NetAcceptSocket.cs
@@ -100,7 +100,7 @@ namespace Emby.Common.Implementations.Net
#if NET46
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>();
diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Common.Implementations/Net/SocketFactory.cs
index 021613e57..0f4306a6b 100644
--- a/Emby.Common.Implementations/Net/SocketFactory.cs
+++ b/Emby.Common.Implementations/Net/SocketFactory.cs
@@ -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>
- /// 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>
- /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
+ /// 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>
+ /// <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)
{
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs
index 8e2a1da6f..b85245ba1 100644
--- a/Emby.Common.Implementations/Net/UdpSocket.cs
+++ b/Emby.Common.Implementations/Net/UdpSocket.cs
@@ -60,6 +60,8 @@ namespace Emby.Common.Implementations.Net
var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
state.TaskCompletionSource = tcs;
+ cancellationToken.Register(() => tcs.TrySetCanceled());
+
#if NETSTANDARD1_6
_Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer), SocketFlags.None, state.RemoteEndPoint)
.ContinueWith((task, asyncState) =>
@@ -160,7 +162,7 @@ namespace Emby.Common.Implementations.Net
var bytesRead = receiveData();
var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
- state.TaskCompletionSource.SetResult(
+ state.TaskCompletionSource.TrySetResult(
new SocketReceiveResult
{
Buffer = state.Buffer,
@@ -172,18 +174,18 @@ namespace Emby.Common.Implementations.Net
}
catch (ObjectDisposedException)
{
- state.TaskCompletionSource.SetCanceled();
+ state.TaskCompletionSource.TrySetCanceled();
}
catch (SocketException se)
{
if (se.SocketErrorCode != SocketError.Interrupted && se.SocketErrorCode != SocketError.OperationAborted && se.SocketErrorCode != SocketError.Shutdown)
- state.TaskCompletionSource.SetException(se);
+ state.TaskCompletionSource.TrySetException(se);
else
- state.TaskCompletionSource.SetCanceled();
+ state.TaskCompletionSource.TrySetCanceled();
}
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 ipEndPoint = state.RemoteEndPoint as IPEndPoint;
- state.TaskCompletionSource.SetResult(
+ state.TaskCompletionSource.TrySetResult(
new SocketReceiveResult
{
Buffer = state.Buffer,
@@ -218,11 +220,11 @@ namespace Emby.Common.Implementations.Net
}
catch (ObjectDisposedException)
{
- state.TaskCompletionSource.SetCanceled();
+ state.TaskCompletionSource.TrySetCanceled();
}
catch (Exception ex)
{
- state.TaskCompletionSource.SetException(ex);
+ state.TaskCompletionSource.TrySetException(ex);
}
#endif
}
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index a15f75c9a..5b04ceea2 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -238,7 +238,7 @@ namespace Emby.Drawing
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 imageProcessingLockTaken = false;
+ //var imageProcessingLockTaken = false;
try
{
@@ -253,9 +253,9 @@ namespace Emby.Drawing
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
_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);
CopyFile(tmpPath, cacheFilePath);
@@ -273,13 +273,13 @@ namespace Emby.Drawing
// Just spit out the original file if all the options are default
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
- finally
- {
- if (imageProcessingLockTaken)
- {
- _imageProcessingSemaphore.Release();
- }
- }
+ //finally
+ //{
+ // if (imageProcessingLockTaken)
+ // {
+ // _imageProcessingSemaphore.Release();
+ // }
+ //}
}
private void CopyFile(string src, string destination)
diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
index 2819a249f..0096f2284 100644
--- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
+++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities.Audio;
@@ -22,13 +23,15 @@ namespace Emby.Server.Implementations.Data
private readonly IItemRepository _itemRepo;
private readonly ILogger _logger;
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;
_itemRepo = itemRepo;
_logger = logger;
_fileSystem = fileSystem;
+ _appPaths = appPaths;
}
public string Name
@@ -150,13 +153,27 @@ namespace Emby.Server.Implementations.Data
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);
+ if (libraryItem == null)
+ {
+ continue;
+ }
+
if (libraryItem.IsTopParent)
{
continue;
@@ -180,7 +197,14 @@ namespace Emby.Server.Implementations.Data
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);
}
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index d873cd77f..ecd86d507 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -171,7 +171,6 @@
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
<Compile Include="LiveTv\TunerHosts\BaseTunerHost.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\HdHomerunHttpStream.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index b80a40962..d230a9b91 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -27,6 +27,8 @@ namespace Emby.Server.Implementations.HttpServer
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public List<Cookie> Cookies { get; private set; }
+ public FileShareMode FileShare { get; set; }
+
/// <summary>
/// The _options
/// </summary>
@@ -69,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer
SetRangeValues();
}
+ FileShare = FileShareMode.Read;
Cookies = new List<Cookie>();
}
@@ -153,11 +156,11 @@ namespace Emby.Server.Implementations.HttpServer
if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
{
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;
}
- await response.TransmitFile(Path, RangeStart, RangeEnd, cancellationToken).ConfigureAwait(false);
+ await response.TransmitFile(Path, RangeStart, RangeEnd, FileShare, cancellationToken).ConfigureAwait(false);
}
finally
{
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index e3f105941..310161d41 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -556,12 +556,13 @@ namespace Emby.Server.Implementations.HttpServer
{
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)
{
OnComplete = options.OnComplete,
- OnError = options.OnError
+ OnError = options.OnError,
+ FileShare = options.FileShare
};
}
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index a497ee715..fd30b227f 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -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);
}
}
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index f7706db47..026486efc 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -514,6 +514,11 @@ namespace Emby.Server.Implementations.Library
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))
{
throw new ArgumentNullException("key");
@@ -531,7 +536,7 @@ namespace Emby.Server.Implementations.Library
.Replace("/", "\\");
}
- if (!ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
+ if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
{
key = key.ToLower();
}
@@ -865,7 +870,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Person}.</returns>
public Person GetPerson(string name)
{
- return CreateItemByName<Person>(Person.GetPath(name), name);
+ return CreateItemByName<Person>(Person.GetPath, name);
}
/// <summary>
@@ -875,7 +880,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Studio}.</returns>
public Studio GetStudio(string name)
{
- return CreateItemByName<Studio>(Studio.GetPath(name), name);
+ return CreateItemByName<Studio>(Studio.GetPath, name);
}
/// <summary>
@@ -885,7 +890,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public Genre GetGenre(string name)
{
- return CreateItemByName<Genre>(Genre.GetPath(name), name);
+ return CreateItemByName<Genre>(Genre.GetPath, name);
}
/// <summary>
@@ -895,7 +900,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{MusicGenre}.</returns>
public MusicGenre GetMusicGenre(string name)
{
- return CreateItemByName<MusicGenre>(MusicGenre.GetPath(name), name);
+ return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name);
}
/// <summary>
@@ -905,7 +910,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{GameGenre}.</returns>
public GameGenre GetGameGenre(string name)
{
- return CreateItemByName<GameGenre>(GameGenre.GetPath(name), name);
+ return CreateItemByName<GameGenre>(GameGenre.GetPath, name);
}
/// <summary>
@@ -923,7 +928,7 @@ namespace Emby.Server.Implementations.Library
var name = value.ToString(CultureInfo.InvariantCulture);
- return CreateItemByName<Year>(Year.GetPath(name), name);
+ return CreateItemByName<Year>(Year.GetPath, name);
}
/// <summary>
@@ -933,10 +938,10 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
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()
{
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;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index d9060a066..a7ccafd69 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -2542,6 +2542,60 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public ProgramInfo Program { 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
{
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 618cd1d45..de39d3838 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -150,6 +150,16 @@ namespace Emby.Server.Implementations.LiveTv
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)
{
if (!_isDisposed)
@@ -1180,6 +1190,8 @@ namespace Emby.Server.Implementations.LiveTv
{
EmbyTV.EmbyTV.Current.CreateRecordingFolders();
+ await EmbyTV.EmbyTV.Current.ScanForTunerDeviceChanges(cancellationToken).ConfigureAwait(false);
+
var numComplete = 0;
double progressPerService = _services.Count == 0
? 0
@@ -2748,7 +2760,7 @@ namespace Emby.Server.Implementations.LiveTv
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()
@@ -2986,7 +2998,7 @@ namespace Emby.Server.Implementations.LiveTv
if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
{
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)
{
return Task.FromResult(new MBRegistrationRecord
@@ -3000,50 +3012,6 @@ namespace Emby.Server.Implementations.LiveTv
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)
{
var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
index f2806292d..5582d8f35 100644
--- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
+++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv
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
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 5ac3812b0..79fa9bb61 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected virtual List<TunerHostInfo> GetTunerHosts()
{
return GetConfiguration().TunerHosts
- .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
+ .Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
.ToList();
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
deleted file mode 100644
index 336469c50..000000000
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
+++ /dev/null
@@ -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()
- {
- }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 62385e172..dbcabd174 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var list = new List<LiveTvTunerInfo>();
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
{
@@ -587,7 +587,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
- {
+ {
var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
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)
{
- if (!info.IsEnabled)
- {
- return;
- }
-
lock (_modelCache)
{
_modelCache.Clear();
@@ -652,5 +647,74 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public string LineupURL { 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;
+ }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index a939cec7b..cc0ae0983 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -176,5 +176,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
return Task.FromResult(true);
}
+
+ public Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(new List<TunerHostInfo>());
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index dc4e57155..639021762 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -582,13 +582,13 @@ namespace MediaBrowser.Api.LiveTv
}
[Route("/LiveTv/ListingProviders/Default", "GET")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class GetDefaultListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
{
}
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
{
public bool ValidateLogin { get; set; }
@@ -596,7 +596,7 @@ namespace MediaBrowser.Api.LiveTv
}
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class DeleteListingProvider : IReturnVoid
{
[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")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class GetLineups : IReturn<List<NameIdPair>>
{
[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")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class GetSchedulesDirectCountries
{
}
[Route("/LiveTv/ChannelMappingOptions")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class GetChannelMappingOptions
{
[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")]
- [Authenticated(AllowBeforeStartupWizard = true)]
+ [Authenticated]
public class SetChannelMapping
{
[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; }
}
- [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")]
public class GetLiveStreamFile
{
@@ -687,6 +673,13 @@ namespace MediaBrowser.Api.LiveTv
public string Id { get; set; }
}
+ [Route("/LiveTv/TunerHosts/Types", "GET")]
+ [Authenticated]
+ public class GetTunerHostTypes : IReturn<List<NameIdPair>>
+ {
+
+ }
+
public class LiveTvService : BaseApiService
{
private readonly ILiveTvManager _liveTvManager;
@@ -712,6 +705,12 @@ namespace MediaBrowser.Api.LiveTv
_sessionContext = sessionContext;
}
+ public object Get(GetTunerHostTypes request)
+ {
+ var list = _liveTvManager.GetTunerHostTypes();
+ return ToOptimizedResult(list);
+ }
+
public object Get(GetLiveRecordingFile request)
{
var path = _liveTvManager.GetEmbyTvActiveRecordingPath(request.Id);
@@ -749,13 +748,6 @@ namespace MediaBrowser.Api.LiveTv
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)
{
var result = await _liveTvManager.GetRegistrationInfo(request.Feature).ConfigureAwait(false);
@@ -803,11 +795,6 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
- public object Get(GetSatIniMappings request)
- {
- return ToOptimizedResult(_liveTvManager.GetSatIniMappings());
- }
-
public async Task<object> Get(GetSchedulesDirectCountries request)
{
// https://json.schedulesdirect.org/20141201/available/countries
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index e010f122c..b0f52dd85 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -1,12 +1,9 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.LiveTv;
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -52,16 +49,14 @@ namespace MediaBrowser.Api
private readonly IServerApplicationHost _appHost;
private readonly IUserManager _userManager;
private readonly IConnectManager _connectManager;
- private readonly ILiveTvManager _liveTvManager;
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;
_appHost = appHost;
_userManager = userManager;
_connectManager = connectManager;
- _liveTvManager = liveTvManager;
_mediaEncoder = mediaEncoder;
}
@@ -92,20 +87,6 @@ namespace MediaBrowser.Api
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;
}
@@ -120,6 +101,7 @@ namespace MediaBrowser.Api
config.EnableSeriesPresentationUniqueKey = true;
config.EnableLocalizedGuids = true;
config.EnableSimpleArtistDetection = true;
+ config.EnableNormalizedItemByNameIds = true;
}
public void Post(UpdateStartupConfiguration request)
@@ -128,9 +110,6 @@ namespace MediaBrowser.Api
_config.Configuration.MetadataCountryCode = request.MetadataCountryCode;
_config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage;
_config.SaveConfiguration();
-
- var task = UpdateTuners(request);
- Task.WaitAll(task);
}
public object Get(GetStartupUser request)
@@ -165,51 +144,6 @@ namespace MediaBrowser.Api
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
@@ -217,10 +151,6 @@ namespace MediaBrowser.Api
public string UICulture { get; set; }
public string MetadataCountryCode { 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
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 20b2529c0..8d83f8a35 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index 74679b474..e26e0dfce 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -118,7 +118,12 @@ namespace MediaBrowser.Controller.Entities.Audio
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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
index 22a8675c5..4187167b9 100644
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ b/MediaBrowser.Controller/Entities/GameGenre.cs
@@ -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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 1b746ae51..9769efdd0 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index ee1aea938..b68681d36 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -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
var validFilename = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index b8ad691a9..2e5e6ce43 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 75fb69435..b352950a0 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -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
var validName = normalizeName ?
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index a908d2d3f..b3467fbbc 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -376,19 +376,13 @@ namespace MediaBrowser.Controller.LiveTv
/// <returns>Task.</returns>
Task OnRecordingFileDeleted(BaseItem recording);
- /// <summary>
- /// Gets the sat ini mappings.
- /// </summary>
- /// <returns>List&lt;NameValuePair&gt;.</returns>
- List<NameValuePair> GetSatIniMappings();
-
- Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
-
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
List<IListingsProvider> ListingProviders { get; }
+ List<NameIdPair> GetTunerHostTypes();
+
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index 5615649c2..fc344298b 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -44,6 +44,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
+
+ Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken);
}
public interface IConfigurableTunerHost
{
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index c2b1e3c89..0562d0ac5 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -48,6 +48,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableHttps { get; set; }
public bool EnableSeriesPresentationUniqueKey { get; set; }
public bool EnableLocalizedGuids { get; set; }
+ public bool EnableNormalizedItemByNameIds { get; set; }
/// <summary>
/// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 79a484a46..6a0fdede3 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -46,14 +46,13 @@ namespace MediaBrowser.Model.LiveTv
public string Url { get; set; }
public string Type { get; set; }
public string DeviceId { get; set; }
+ public string FriendlyName { get; set; }
public bool ImportFavoritesOnly { get; set; }
public bool AllowHWTranscoding { get; set; }
- public bool IsEnabled { get; set; }
public bool EnableTvgId { get; set; }
public TunerHostInfo()
{
- IsEnabled = true;
AllowHWTranscoding = true;
}
}
diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs
index 4b70f3362..e7dbf6cb1 100644
--- a/MediaBrowser.Model/Net/ISocketFactory.cs
+++ b/MediaBrowser.Model/Net/ISocketFactory.cs
@@ -14,6 +14,8 @@ namespace MediaBrowser.Model.Net
/// <returns>A <see cref="ISocket"/> implementation.</returns>
ISocket CreateUdpSocket(int localPort);
+ ISocket CreateUdpBroadcastSocket(int localPort);
+
ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
/// <summary>
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
index 40cef4ec0..115ba25ce 100644
--- a/MediaBrowser.Model/Services/IRequest.cs
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.IO;
namespace MediaBrowser.Model.Services
{
@@ -154,6 +155,6 @@ namespace MediaBrowser.Model.Services
//Add Metadata to Response
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);
}
}
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 3f2c5d97e..825a8b919 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.7.3")]
+[assembly: AssemblyVersion("3.2.7.4")]
diff --git a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
index d8011f05e..d9f91c0cc 100644
--- a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
+++ b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
@@ -515,9 +515,9 @@ namespace SocketHttpListener.Net
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);
}
}
} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs
index ccc0efc55..19821f954 100644
--- a/SocketHttpListener.Portable/Net/ResponseStream.cs
+++ b/SocketHttpListener.Portable/Net/ResponseStream.cs
@@ -307,13 +307,13 @@ namespace SocketHttpListener.Net
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)
//{
// 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[] { };
@@ -334,7 +334,7 @@ namespace SocketHttpListener.Net
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;
@@ -343,7 +343,7 @@ namespace SocketHttpListener.Net
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)
{