update query fields

This commit is contained in:
Luke Pulverenti
2017-05-22 00:54:02 -04:00
parent 41ea0d99f4
commit 54cf0da758
41 changed files with 622 additions and 387 deletions

View File

@@ -1415,66 +1415,69 @@ namespace Emby.Server.Implementations.Data
var index = 5;
var hasProgramAttributes = item as IHasProgramAttributes;
if (hasProgramAttributes != null)
if (HasProgramAttributes(query))
{
if (!reader.IsDBNull(index))
var hasProgramAttributes = item as IHasProgramAttributes;
if (hasProgramAttributes != null)
{
hasProgramAttributes.IsMovie = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsMovie = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsSports = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsSports = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsKids = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsKids = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsSeries = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsSeries = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsLive = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsLive = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsNews = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsNews = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.EpisodeTitle = reader.GetString(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.EpisodeTitle = reader.GetString(index);
}
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
}
index++;
}
else
{
index += 9;
}
index++;
}
else
{
index += 9;
}
if (!reader.IsDBNull(index))
@@ -1483,7 +1486,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.CustomRating))
if (HasField(query, ItemFields.CustomRating))
{
if (!reader.IsDBNull(index))
{
@@ -1498,7 +1501,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.Settings))
if (HasField(query, ItemFields.Settings))
{
if (!reader.IsDBNull(index))
{
@@ -1525,7 +1528,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.ExternalEtag))
if (HasField(query, ItemFields.ExternalEtag))
{
if (!reader.IsDBNull(index))
{
@@ -1534,11 +1537,14 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (!reader.IsDBNull(index))
if (HasField(query, ItemFields.DateLastRefreshed))
{
item.DateLastRefreshed = reader[index].ReadDateTime();
if (!reader.IsDBNull(index))
{
item.DateLastRefreshed = reader[index].ReadDateTime();
}
index++;
}
index++;
if (!reader.IsDBNull(index))
{
@@ -1558,7 +1564,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.Overview))
if (HasField(query, ItemFields.Overview))
{
if (!reader.IsDBNull(index))
{
@@ -1585,7 +1591,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.HomePageUrl))
if (HasField(query, ItemFields.HomePageUrl))
{
if (!reader.IsDBNull(index))
{
@@ -1594,7 +1600,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.DisplayMediaType))
if (HasField(query, ItemFields.DisplayMediaType))
{
if (!reader.IsDBNull(index))
{
@@ -1603,7 +1609,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.SortName))
if (HasField(query, ItemFields.SortName))
{
if (!reader.IsDBNull(index))
{
@@ -1618,7 +1624,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.VoteCount))
if (HasField(query, ItemFields.VoteCount))
{
if (!reader.IsDBNull(index))
{
@@ -1627,7 +1633,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.DateCreated))
if (HasField(query, ItemFields.DateCreated))
{
if (!reader.IsDBNull(index))
{
@@ -1645,7 +1651,7 @@ namespace Emby.Server.Implementations.Data
item.Id = reader.GetGuid(index);
index++;
if (query.HasField(ItemFields.Genres))
if (HasField(query, ItemFields.Genres))
{
if (!reader.IsDBNull(index))
{
@@ -1680,13 +1686,16 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (!reader.IsDBNull(index))
if (HasField(query, ItemFields.DateLastSaved))
{
item.DateLastSaved = reader[index].ReadDateTime();
if (!reader.IsDBNull(index))
{
item.DateLastSaved = reader[index].ReadDateTime();
}
index++;
}
index++;
if (query.HasField(ItemFields.Settings))
if (HasField(query, ItemFields.Settings))
{
if (!reader.IsDBNull(index))
{
@@ -1695,7 +1704,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.Studios))
if (HasField(query, ItemFields.Studios))
{
if (!reader.IsDBNull(index))
{
@@ -1704,7 +1713,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.Tags))
if (HasField(query, ItemFields.Tags))
{
if (!reader.IsDBNull(index))
{
@@ -1729,7 +1738,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.OriginalTitle))
if (HasField(query, ItemFields.OriginalTitle))
{
if (!reader.IsDBNull(index))
{
@@ -1748,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.DateLastMediaAdded))
if (HasField(query, ItemFields.DateLastMediaAdded))
{
var folder = item as Folder;
if (folder != null && !reader.IsDBNull(index))
@@ -1814,7 +1823,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (query.HasField(ItemFields.PresentationUniqueKey))
if (HasField(query, ItemFields.PresentationUniqueKey))
{
if (!reader.IsDBNull(index))
{
@@ -1823,7 +1832,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.InheritedParentalRatingValue))
if (HasField(query, ItemFields.InheritedParentalRatingValue))
{
if (!reader.IsDBNull(index))
{
@@ -1832,7 +1841,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.Tags))
if (HasField(query, ItemFields.Tags))
{
if (!reader.IsDBNull(index))
{
@@ -1841,7 +1850,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.ExternalSeriesId))
if (HasField(query, ItemFields.ExternalSeriesId))
{
if (!reader.IsDBNull(index))
{
@@ -1850,7 +1859,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.Taglines))
if (HasField(query, ItemFields.Taglines))
{
if (!reader.IsDBNull(index))
{
@@ -1859,7 +1868,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.Keywords))
if (HasField(query, ItemFields.Keywords))
{
if (!reader.IsDBNull(index))
{
@@ -1883,7 +1892,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.ProductionLocations))
if (HasField(query, ItemFields.ProductionLocations))
{
if (!reader.IsDBNull(index))
{
@@ -1892,7 +1901,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.ThemeSongIds))
if (HasField(query, ItemFields.ThemeSongIds))
{
if (!reader.IsDBNull(index))
{
@@ -1901,7 +1910,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
if (query.HasField(ItemFields.ThemeVideoIds))
if (HasField(query, ItemFields.ThemeVideoIds))
{
if (!reader.IsDBNull(index))
{
@@ -1942,14 +1951,17 @@ namespace Emby.Server.Implementations.Data
}
index++;
if (hasSeries != null)
if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
{
if (!reader.IsDBNull(index))
if (hasSeries != null)
{
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
if (!reader.IsDBNull(index))
{
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
}
}
index++;
}
index++;
return item;
}
@@ -2259,13 +2271,73 @@ namespace Emby.Server.Implementations.Data
return new[] { field.ToString() };
}
private bool HasField(InternalItemsQuery query, ItemFields name)
{
var fields = query.DtoOptions.Fields;
switch (name)
{
case ItemFields.HomePageUrl:
case ItemFields.Keywords:
case ItemFields.DisplayMediaType:
case ItemFields.VoteCount:
case ItemFields.CustomRating:
case ItemFields.ProductionLocations:
case ItemFields.Settings:
case ItemFields.OriginalTitle:
case ItemFields.Taglines:
case ItemFields.SortName:
case ItemFields.Studios:
case ItemFields.Tags:
case ItemFields.ThemeSongIds:
case ItemFields.ThemeVideoIds:
case ItemFields.DateCreated:
case ItemFields.Overview:
case ItemFields.Genres:
case ItemFields.DateLastMediaAdded:
case ItemFields.ExternalEtag:
case ItemFields.PresentationUniqueKey:
case ItemFields.InheritedParentalRatingValue:
case ItemFields.ExternalSeriesId:
case ItemFields.SeriesPresentationUniqueKey:
case ItemFields.DateLastRefreshed:
case ItemFields.DateLastSaved:
return fields.Contains(name);
case ItemFields.ServiceName:
return true;
default:
return true;
}
}
private bool HasProgramAttributes(InternalItemsQuery query)
{
if (query.IncludeItemTypes.Length == 0)
{
return true;
}
var types = new string[]
{
"Program",
"Recording",
"TvChannel",
"LiveTvAudioRecording",
"LiveTvVideoRecording",
"LiveTvProgram",
"LiveTvTvChannel"
};
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
}
private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
{
var list = startColumns.ToList();
foreach (var field in allFields)
{
if (!query.HasField(field))
if (!HasField(query, field))
{
foreach (var fieldToRemove in GetColumnNamesFromField(field).ToList())
{
@@ -2274,6 +2346,19 @@ namespace Emby.Server.Implementations.Data
}
}
if (!HasProgramAttributes(query))
{
list.Remove("IsKids");
list.Remove("IsMovie");
list.Remove("IsSports");
list.Remove("IsSeries");
list.Remove("IsLive");
list.Remove("IsNews");
list.Remove("IsPremiere");
list.Remove("EpisodeTitle");
list.Remove("IsRepeat");
}
if (!query.DtoOptions.EnableImages)
{
list.Remove("Images");
@@ -2400,7 +2485,7 @@ namespace Emby.Server.Implementations.Data
query.Limit = query.Limit.Value + 4;
}
var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new [] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
commandText += GetJoinUserDataText(query);
var whereClauses = GetWhereClauses(query, null);
@@ -3671,6 +3756,7 @@ namespace Emby.Server.Implementations.Data
if (!string.IsNullOrWhiteSpace(query.SlugName))
{
Logger.Info("Searching by SlugName for {0}", query.SlugName);
whereClauses.Add("CleanName=@SlugName");
if (statement != null)
{

View File

@@ -1137,7 +1137,10 @@ namespace Emby.Server.Implementations.Dto
return null;
}
var artist = _libraryManager.GetArtist(i);
var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
{
EnableImages = false
});
if (artist != null)
{
return new NameIdPair
@@ -1186,7 +1189,10 @@ namespace Emby.Server.Implementations.Dto
return null;
}
var artist = _libraryManager.GetArtist(i);
var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
{
EnableImages = false
});
if (artist != null)
{
return new NameIdPair
@@ -1456,7 +1462,7 @@ namespace Emby.Server.Implementations.Dto
var musicAlbum = item as MusicAlbum;
if (musicAlbum != null)
{
var artist = musicAlbum.MusicArtist;
var artist = musicAlbum.GetMusicArtist(new DtoOptions(false));
if (artist != null)
{
return artist;

View File

@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
@@ -445,10 +446,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <param name="url">The URL.</param>
/// <returns>Task.</returns>
protected async Task RequestHandler(IHttpRequest httpReq, Uri url)
protected async Task RequestHandler(IHttpRequest httpReq, Uri url, CancellationToken cancellationToken)
{
var date = DateTime.Now;
var httpRes = httpReq.Response;
@@ -589,7 +587,7 @@ namespace Emby.Server.Implementations.HttpServer
if (handler != null)
{
await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName).ConfigureAwait(false);
await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName, cancellationToken).ConfigureAwait(false);
}
else
{

View File

@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Net;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
@@ -18,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer
/// Gets or sets the request handler.
/// </summary>
/// <value>The request handler.</value>
Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
/// <summary>
/// Gets or sets the web socket handler.

View File

@@ -4,6 +4,7 @@ using SocketHttpListener.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Cryptography;
@@ -50,7 +51,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
}
public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
public Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
@@ -82,10 +83,10 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private void ProcessContext(HttpListenerContext context)
{
//Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness);
Task.Run(() => InitTask(context));
Task.Run(() => InitTask(context, CancellationToken.None));
}
private Task InitTask(HttpListenerContext context)
private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
{
IHttpRequest httpReq = null;
var request = context.Request;
@@ -111,7 +112,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return Task.FromResult(true);
}
return RequestHandler(httpReq, request.Url);
return RequestHandler(httpReq, request.Url, cancellationToken);
}
private void ProcessWebSocketRequest(HttpListenerContext ctx)

View File

@@ -885,7 +885,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Person}.</returns>
public Person GetPerson(string name)
{
return CreateItemByName<Person>(Person.GetPath, name);
return CreateItemByName<Person>(Person.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -895,7 +895,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Studio}.</returns>
public Studio GetStudio(string name)
{
return CreateItemByName<Studio>(Studio.GetPath, name);
return CreateItemByName<Studio>(Studio.GetPath, name, new DtoOptions(true));
}
public Guid GetStudioId(string name)
@@ -925,7 +925,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public Genre GetGenre(string name)
{
return CreateItemByName<Genre>(Genre.GetPath, name);
return CreateItemByName<Genre>(Genre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -935,7 +935,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{MusicGenre}.</returns>
public MusicGenre GetMusicGenre(string name)
{
return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name);
return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -945,7 +945,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{GameGenre}.</returns>
public GameGenre GetGameGenre(string name)
{
return CreateItemByName<GameGenre>(GameGenre.GetPath, name);
return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Library
var name = value.ToString(CultureInfo.InvariantCulture);
return CreateItemByName<Year>(Year.GetPath, name);
return CreateItemByName<Year>(Year.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -973,10 +973,15 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public MusicArtist GetArtist(string name)
{
return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name);
return GetArtist(name, new DtoOptions(true));
}
private T CreateItemByName<T>(Func<string, string> getPathFn, string name)
public MusicArtist GetArtist(string name, DtoOptions options)
{
return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name, options);
}
private T CreateItemByName<T>(Func<string, string> getPathFn, string name, DtoOptions options)
where T : BaseItem, new()
{
if (typeof(T) == typeof(MusicArtist))
@@ -985,7 +990,7 @@ namespace Emby.Server.Implementations.Library
{
IncludeItemTypes = new[] { typeof(T).Name },
Name = name,
DtoOptions = new DtoOptions(true)
DtoOptions = options
}).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
@@ -1029,54 +1034,6 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
public IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items)
{
var names = items
.SelectMany(i => i.AlbumArtists)
.DistinctNames()
.Select(i =>
{
try
{
var artist = GetArtist(i);
return artist;
}
catch
{
// Already logged at lower levels
return null;
}
})
.Where(i => i != null);
return names;
}
public IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items)
{
var names = items
.SelectMany(i => i.AllArtists)
.DistinctNames()
.Select(i =>
{
try
{
var artist = GetArtist(i);
return artist;
}
catch
{
// Already logged at lower levels
return null;
}
})
.Where(i => i != null);
return names;
}
/// <summary>
/// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation.

View File

@@ -1234,8 +1234,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
BufferMs = 0,
IgnoreDts = true,
IgnoreIndex = true,
GenPtsInput = true
IgnoreIndex = true
};
var isAudio = false;

View File

@@ -479,7 +479,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!(service is EmbyTV.EmbyTV))
{
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
mediaSource.SupportsDirectPlay = false;
//mediaSource.SupportsDirectPlay = false;
mediaSource.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams)

View File

@@ -422,8 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true,
IsInfiniteStream = true,
IgnoreDts = true,
IgnoreIndex = true,
GenPtsInput = true
IgnoreIndex = true
};
mediaSource.InferTotalBitrate();
@@ -507,12 +506,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{
return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
// The UDP method is not working reliably on OSX, and on BSD it hasn't been tested yet
var enableHttpStream = _environment.OperatingSystem == OperatingSystem.OSX ||
_environment.OperatingSystem == OperatingSystem.BSD;
var enableHttpStream = _environment.OperatingSystem == OperatingSystem.OSX
|| _environment.OperatingSystem == OperatingSystem.BSD;
enableHttpStream = true;
if (enableHttpStream)
{
@@ -521,17 +520,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var httpUrl = GetApiUrl(info, true) + "/auto/v" + hdhrId;
// If raw was used, the tuner doesn't support params
if (!string.IsNullOrWhiteSpace(profile)
&& !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
{
httpUrl += "?transcode=" + profile;
}
mediaSource.Path = httpUrl;
return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
}
return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
public async Task Validate(TunerHostInfo info)

View File

@@ -10,6 +10,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
@@ -17,24 +18,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
private readonly MulticastStream _multicastStream;
public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
: base(mediaSource)
private readonly string _tempFilePath;
public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment)
: base(mediaSource, environment, fileSystem)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_logger = logger;
_appPaths = appPaths;
_appHost = appHost;
OriginalStreamId = originalStreamId;
_multicastStream = new MulticastStream(_logger);
_tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
}
protected override async Task OpenInternal(CancellationToken openCancellationToken)
@@ -74,9 +73,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task;
}
private async Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
private Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
await Task.Run(async () =>
return Task.Run(async () =>
{
var isFirstAttempt = true;
@@ -101,13 +100,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
_logger.Info("Beginning multicastStream.CopyUntilCancelled");
Action onStarted = null;
if (isFirstAttempt)
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.Asynchronous | FileOpenOptions.SequentialScan))
{
onStarted = () => openTaskCompletionSource.TrySetResult(true);
}
ResolveAfterDelay(2000, openTaskCompletionSource);
await _multicastStream.CopyUntilCancelled(response.Content, onStarted, cancellationToken).ConfigureAwait(false);
await response.Content.CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false);
}
}
}
}
@@ -131,13 +130,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
_liveStreamTaskCompletionSource.TrySetResult(true);
await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
});
}
}).ConfigureAwait(false);
private void ResolveAfterDelay(int delayMs, TaskCompletionSource<bool> openTaskCompletionSource)
{
Task.Run(async () =>
{
await Task.Delay(delayMs).ConfigureAwait(false);
openTaskCompletionSource.TrySetResult(true);
});
}
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
return _multicastStream.CopyToAsync(stream , cancellationToken);
return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
}
}
}

View File

@@ -46,10 +46,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class HdHomerunChannelCommands : IHdHomerunChannelCommands
{
private string _channel;
private string _profile;
public HdHomerunChannelCommands(string channel)
public HdHomerunChannelCommands(string channel, string profile)
{
_channel = channel;
_profile = profile;
}
public IEnumerable<Tuple<string, string>> GetCommands()
@@ -57,7 +59,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var commands = new List<Tuple<string, string>>();
if (!String.IsNullOrEmpty(_channel))
commands.Add(Tuple.Create("vchannel", _channel));
{
if (!string.IsNullOrWhiteSpace(_profile) && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase))
{
commands.Add(Tuple.Create("vchannel", String.Format("{0} transcode={1}", _channel, _profile)));
}
else
{
commands.Add(Tuple.Create("vchannel", _channel));
}
}
return commands;
}

View File

@@ -14,39 +14,35 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider
{
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
private readonly MulticastStream _multicastStream;
private readonly IHdHomerunChannelCommands _channelCommands;
private readonly int _numTuners;
private readonly INetworkManager _networkManager;
public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager)
: base(mediaSource)
private readonly string _tempFilePath;
public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment)
: base(mediaSource, environment, fileSystem)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_logger = logger;
_appPaths = appPaths;
_appHost = appHost;
_socketFactory = socketFactory;
_networkManager = networkManager;
OriginalStreamId = originalStreamId;
_multicastStream = new MulticastStream(_logger);
_channelCommands = channelCommands;
_numTuners = numTuners;
_tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
}
protected override async Task OpenInternal(CancellationToken openCancellationToken)
@@ -87,9 +83,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task;
}
private async Task StartStreaming(string remoteIp, int localPort, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
private Task StartStreaming(string remoteIp, int localPort, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
await Task.Run(async () =>
return Task.Run(async () =>
{
var isFirstAttempt = true;
using (var udpClient = _socketFactory.CreateUdpSocket(localPort))
@@ -124,13 +120,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (!cancellationToken.IsCancellationRequested)
{
Action onStarted = null;
if (isFirstAttempt)
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.Asynchronous | FileOpenOptions.SequentialScan))
{
onStarted = () => openTaskCompletionSource.TrySetResult(true);
}
ResolveAfterDelay(2000, openTaskCompletionSource);
await _multicastStream.CopyUntilCancelled(new UdpClientStream(udpClient), onStarted, cancellationToken).ConfigureAwait(false);
await new UdpClientStream(udpClient).CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false);
}
}
}
catch (OperationCanceledException ex)
@@ -159,12 +155,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
}).ConfigureAwait(false);
await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
});
}
private void ResolveAfterDelay(int delayMs, TaskCompletionSource<bool> openTaskCompletionSource)
{
Task.Run(async () =>
{
await Task.Delay(delayMs).ConfigureAwait(false);
openTaskCompletionSource.TrySetResult(true);
});
}
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
return _multicastStream.CopyToAsync(stream, cancellationToken);
return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
}
}
@@ -198,7 +204,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// This will always receive a 1328 packet size (PacketSize + RtpHeaderSize)
// The RTP header will be stripped so see how many reads we need to make to fill the buffer.
int numReads = count / PacketSize;
var numReads = count / PacketSize;
int totalBytesRead = 0;
for (int i = 0; i < numReads; ++i)
@@ -206,7 +213,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var data = await _udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
// remove rtp header
Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, buffer, offset, bytesRead);
offset += bytesRead;
@@ -224,7 +231,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
throw new NotImplementedException();
return true;
}
}
@@ -232,7 +239,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
throw new NotImplementedException();
return false;
}
}
@@ -240,7 +247,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
throw new NotImplementedException();
return false;
}
}

View File

@@ -19,6 +19,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
@@ -27,13 +28,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
private readonly IEnvironmentInfo _environment;
public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment)
: base(config, logger, jsonSerializer, mediaEncoder)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_appHost = appHost;
_environment = environment;
}
public override string Type
@@ -73,7 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
var liveStream = new LiveStream(sources.First());
var liveStream = new LiveStream(sources.First(), _environment, _fileSystem);
return liveStream;
}

View File

@@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Services
{
public static class ResponseHelper
{
public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result)
public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result, CancellationToken cancellationToken)
{
if (result == null)
{
@@ -30,21 +30,17 @@ namespace Emby.Server.Implementations.Services
{
httpResult.RequestContext = httpReq;
httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType;
return WriteToResponseInternal(httpRes, httpResult, httpReq);
return WriteToResponseInternal(httpRes, httpResult, httpReq, cancellationToken);
}
return WriteToResponseInternal(httpRes, result, httpReq);
return WriteToResponseInternal(httpRes, result, httpReq, cancellationToken);
}
/// <summary>
/// Writes to response.
/// Response headers are customizable by implementing IHasHeaders an returning Dictionary of Http headers.
/// </summary>
/// <param name="response">The response.</param>
/// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
/// <param name="request">The serialization context.</param>
/// <returns></returns>
private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request)
private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request, CancellationToken cancellationToken)
{
var defaultContentType = request.ResponseContentType;
@@ -105,7 +101,7 @@ namespace Emby.Server.Implementations.Services
var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null)
{
await asyncStreamWriter.WriteToAsync(response.OutputStream, CancellationToken.None).ConfigureAwait(false);
await asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken).ConfigureAwait(false);
return;
}
@@ -119,7 +115,7 @@ namespace Emby.Server.Implementations.Services
var fileWriter = result as FileWriter;
if (fileWriter != null)
{
await fileWriter.WriteToAsync(response, CancellationToken.None).ConfigureAwait(false);
await fileWriter.WriteToAsync(response, cancellationToken).ConfigureAwait(false);
return;
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Logging;
@@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Services
// Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; }
public async Task ProcessRequestAsync(HttpListenerHost appHost, IRequest httpReq, IResponse httpRes, ILogger logger, string operationName)
public async Task ProcessRequestAsync(HttpListenerHost appHost, IRequest httpReq, IResponse httpRes, ILogger logger, string operationName, CancellationToken cancellationToken)
{
var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null)
@@ -150,7 +151,7 @@ namespace Emby.Server.Implementations.Services
responseFilter(httpReq, httpRes, response);
}
await ResponseHelper.WriteToResponse(httpRes, httpReq, response).ConfigureAwait(false);
await ResponseHelper.WriteToResponse(httpRes, httpReq, response, cancellationToken).ConfigureAwait(false);
}
public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, ILogger logger)