update query fields

pull/1154/head
Luke Pulverenti 8 years ago
parent 41ea0d99f4
commit 54cf0da758

@ -1415,6 +1415,8 @@ namespace Emby.Server.Implementations.Data
var index = 5; var index = 5;
if (HasProgramAttributes(query))
{
var hasProgramAttributes = item as IHasProgramAttributes; var hasProgramAttributes = item as IHasProgramAttributes;
if (hasProgramAttributes != null) if (hasProgramAttributes != null)
{ {
@ -1476,6 +1478,7 @@ namespace Emby.Server.Implementations.Data
{ {
index += 9; index += 9;
} }
}
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1483,7 +1486,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.CustomRating)) if (HasField(query, ItemFields.CustomRating))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1498,7 +1501,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.Settings)) if (HasField(query, ItemFields.Settings))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1525,7 +1528,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.ExternalEtag)) if (HasField(query, ItemFields.ExternalEtag))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1534,11 +1537,14 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (HasField(query, ItemFields.DateLastRefreshed))
{
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.DateLastRefreshed = reader[index].ReadDateTime(); item.DateLastRefreshed = reader[index].ReadDateTime();
} }
index++; index++;
}
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1558,7 +1564,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.Overview)) if (HasField(query, ItemFields.Overview))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1585,7 +1591,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.HomePageUrl)) if (HasField(query, ItemFields.HomePageUrl))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1594,7 +1600,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.DisplayMediaType)) if (HasField(query, ItemFields.DisplayMediaType))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1603,7 +1609,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.SortName)) if (HasField(query, ItemFields.SortName))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1618,7 +1624,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.VoteCount)) if (HasField(query, ItemFields.VoteCount))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1627,7 +1633,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.DateCreated)) if (HasField(query, ItemFields.DateCreated))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1645,7 +1651,7 @@ namespace Emby.Server.Implementations.Data
item.Id = reader.GetGuid(index); item.Id = reader.GetGuid(index);
index++; index++;
if (query.HasField(ItemFields.Genres)) if (HasField(query, ItemFields.Genres))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1680,13 +1686,16 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (HasField(query, ItemFields.DateLastSaved))
{
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
item.DateLastSaved = reader[index].ReadDateTime(); item.DateLastSaved = reader[index].ReadDateTime();
} }
index++; index++;
}
if (query.HasField(ItemFields.Settings)) if (HasField(query, ItemFields.Settings))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1695,7 +1704,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.Studios)) if (HasField(query, ItemFields.Studios))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1704,7 +1713,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.Tags)) if (HasField(query, ItemFields.Tags))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1729,7 +1738,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.OriginalTitle)) if (HasField(query, ItemFields.OriginalTitle))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1748,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.DateLastMediaAdded)) if (HasField(query, ItemFields.DateLastMediaAdded))
{ {
var folder = item as Folder; var folder = item as Folder;
if (folder != null && !reader.IsDBNull(index)) if (folder != null && !reader.IsDBNull(index))
@ -1814,7 +1823,7 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (query.HasField(ItemFields.PresentationUniqueKey)) if (HasField(query, ItemFields.PresentationUniqueKey))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1823,7 +1832,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.InheritedParentalRatingValue)) if (HasField(query, ItemFields.InheritedParentalRatingValue))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1832,7 +1841,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.Tags)) if (HasField(query, ItemFields.Tags))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1841,7 +1850,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.ExternalSeriesId)) if (HasField(query, ItemFields.ExternalSeriesId))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1850,7 +1859,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.Taglines)) if (HasField(query, ItemFields.Taglines))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1859,7 +1868,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.Keywords)) if (HasField(query, ItemFields.Keywords))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1883,7 +1892,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.ProductionLocations)) if (HasField(query, ItemFields.ProductionLocations))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1892,7 +1901,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.ThemeSongIds)) if (HasField(query, ItemFields.ThemeSongIds))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1901,7 +1910,7 @@ namespace Emby.Server.Implementations.Data
index++; index++;
} }
if (query.HasField(ItemFields.ThemeVideoIds)) if (HasField(query, ItemFields.ThemeVideoIds))
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
{ {
@ -1942,6 +1951,8 @@ namespace Emby.Server.Implementations.Data
} }
index++; index++;
if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
{
if (hasSeries != null) if (hasSeries != null)
{ {
if (!reader.IsDBNull(index)) if (!reader.IsDBNull(index))
@ -1950,6 +1961,7 @@ namespace Emby.Server.Implementations.Data
} }
} }
index++; index++;
}
return item; return item;
} }
@ -2259,13 +2271,73 @@ namespace Emby.Server.Implementations.Data
return new[] { field.ToString() }; 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) private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
{ {
var list = startColumns.ToList(); var list = startColumns.ToList();
foreach (var field in allFields) foreach (var field in allFields)
{ {
if (!query.HasField(field)) if (!HasField(query, field))
{ {
foreach (var fieldToRemove in GetColumnNamesFromField(field).ToList()) 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) if (!query.DtoOptions.EnableImages)
{ {
list.Remove("Images"); list.Remove("Images");
@ -3671,6 +3756,7 @@ namespace Emby.Server.Implementations.Data
if (!string.IsNullOrWhiteSpace(query.SlugName)) if (!string.IsNullOrWhiteSpace(query.SlugName))
{ {
Logger.Info("Searching by SlugName for {0}", query.SlugName);
whereClauses.Add("CleanName=@SlugName"); whereClauses.Add("CleanName=@SlugName");
if (statement != null) if (statement != null)
{ {

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

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

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

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

@ -885,7 +885,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Person}.</returns> /// <returns>Task{Person}.</returns>
public Person GetPerson(string name) public Person GetPerson(string name)
{ {
return CreateItemByName<Person>(Person.GetPath, name); return CreateItemByName<Person>(Person.GetPath, name, new DtoOptions(true));
} }
/// <summary> /// <summary>
@ -895,7 +895,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Studio}.</returns> /// <returns>Task{Studio}.</returns>
public Studio GetStudio(string name) public Studio GetStudio(string name)
{ {
return CreateItemByName<Studio>(Studio.GetPath, name); return CreateItemByName<Studio>(Studio.GetPath, name, new DtoOptions(true));
} }
public Guid GetStudioId(string name) public Guid GetStudioId(string name)
@ -925,7 +925,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns> /// <returns>Task{Genre}.</returns>
public Genre GetGenre(string name) public Genre GetGenre(string name)
{ {
return CreateItemByName<Genre>(Genre.GetPath, name); return CreateItemByName<Genre>(Genre.GetPath, name, new DtoOptions(true));
} }
/// <summary> /// <summary>
@ -935,7 +935,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{MusicGenre}.</returns> /// <returns>Task{MusicGenre}.</returns>
public MusicGenre GetMusicGenre(string name) public MusicGenre GetMusicGenre(string name)
{ {
return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name); return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name, new DtoOptions(true));
} }
/// <summary> /// <summary>
@ -945,7 +945,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{GameGenre}.</returns> /// <returns>Task{GameGenre}.</returns>
public GameGenre GetGameGenre(string name) public GameGenre GetGameGenre(string name)
{ {
return CreateItemByName<GameGenre>(GameGenre.GetPath, name); return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true));
} }
/// <summary> /// <summary>
@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Library
var name = value.ToString(CultureInfo.InvariantCulture); var name = value.ToString(CultureInfo.InvariantCulture);
return CreateItemByName<Year>(Year.GetPath, name); return CreateItemByName<Year>(Year.GetPath, name, new DtoOptions(true));
} }
/// <summary> /// <summary>
@ -973,10 +973,15 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns> /// <returns>Task{Genre}.</returns>
public MusicArtist GetArtist(string name) public MusicArtist GetArtist(string name)
{ {
return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name); 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() where T : BaseItem, new()
{ {
if (typeof(T) == typeof(MusicArtist)) if (typeof(T) == typeof(MusicArtist))
@ -985,7 +990,7 @@ namespace Emby.Server.Implementations.Library
{ {
IncludeItemTypes = new[] { typeof(T).Name }, IncludeItemTypes = new[] { typeof(T).Name },
Name = name, Name = name,
DtoOptions = new DtoOptions(true) DtoOptions = options
}).Cast<MusicArtist>() }).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0) .OrderBy(i => i.IsAccessedByName ? 1 : 0)
@ -1029,54 +1034,6 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId); 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> /// <summary>
/// Validate and refresh the People sub-set of the IBN. /// 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. /// The items are stored in the db but not loaded into memory until actually requested by an operation.

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

@ -479,7 +479,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!(service is EmbyTV.EmbyTV)) 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 // 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.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true; mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams) foreach (var stream in mediaSource.MediaStreams)

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

@ -10,6 +10,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
@ -17,24 +18,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>(); 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) private readonly string _tempFilePath;
: base(mediaSource)
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; _httpClient = httpClient;
_logger = logger; _logger = logger;
_appPaths = appPaths;
_appHost = appHost; _appHost = appHost;
OriginalStreamId = originalStreamId; OriginalStreamId = originalStreamId;
_multicastStream = new MulticastStream(_logger);
_tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
} }
protected override async Task OpenInternal(CancellationToken openCancellationToken) protected override async Task OpenInternal(CancellationToken openCancellationToken)
@ -74,9 +73,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task; 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; var isFirstAttempt = true;
@ -101,13 +100,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
_logger.Info("Beginning multicastStream.CopyUntilCancelled"); _logger.Info("Beginning multicastStream.CopyUntilCancelled");
Action onStarted = null; FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
if (isFirstAttempt) 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); _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) public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{ {
return _multicastStream.CopyToAsync(stream , cancellationToken); return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
} }
} }
} }

@ -46,10 +46,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class HdHomerunChannelCommands : IHdHomerunChannelCommands public class HdHomerunChannelCommands : IHdHomerunChannelCommands
{ {
private string _channel; private string _channel;
private string _profile;
public HdHomerunChannelCommands(string channel) public HdHomerunChannelCommands(string channel, string profile)
{ {
_channel = channel; _channel = channel;
_profile = profile;
} }
public IEnumerable<Tuple<string, string>> GetCommands() public IEnumerable<Tuple<string, string>> GetCommands()
@ -57,7 +59,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var commands = new List<Tuple<string, string>>(); var commands = new List<Tuple<string, string>>();
if (!String.IsNullOrEmpty(_channel)) if (!String.IsNullOrEmpty(_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)); commands.Add(Tuple.Create("vchannel", _channel));
}
}
return commands; return commands;
} }

@ -14,39 +14,35 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory; private readonly ISocketFactory _socketFactory;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>(); private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
private readonly MulticastStream _multicastStream;
private readonly IHdHomerunChannelCommands _channelCommands; private readonly IHdHomerunChannelCommands _channelCommands;
private readonly int _numTuners; private readonly int _numTuners;
private readonly INetworkManager _networkManager; 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) private readonly string _tempFilePath;
: base(mediaSource)
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; _logger = logger;
_appPaths = appPaths;
_appHost = appHost; _appHost = appHost;
_socketFactory = socketFactory; _socketFactory = socketFactory;
_networkManager = networkManager; _networkManager = networkManager;
OriginalStreamId = originalStreamId; OriginalStreamId = originalStreamId;
_multicastStream = new MulticastStream(_logger);
_channelCommands = channelCommands; _channelCommands = channelCommands;
_numTuners = numTuners; _numTuners = numTuners;
_tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
} }
protected override async Task OpenInternal(CancellationToken openCancellationToken) protected override async Task OpenInternal(CancellationToken openCancellationToken)
@ -87,9 +83,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task; 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; var isFirstAttempt = true;
using (var udpClient = _socketFactory.CreateUdpSocket(localPort)) using (var udpClient = _socketFactory.CreateUdpSocket(localPort))
@ -124,13 +120,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (!cancellationToken.IsCancellationRequested) if (!cancellationToken.IsCancellationRequested)
{ {
Action onStarted = null; FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
if (isFirstAttempt) 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) 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) 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) // 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. // 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; int totalBytesRead = 0;
for (int i = 0; i < numReads; ++i) for (int i = 0; i < numReads; ++i)
@ -224,7 +231,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
get get
{ {
throw new NotImplementedException(); return true;
} }
} }
@ -232,7 +239,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
get get
{ {
throw new NotImplementedException(); return false;
} }
} }
@ -240,7 +247,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
get get
{ {
throw new NotImplementedException(); return false;
} }
} }

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

@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Services
{ {
public static class ResponseHelper 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) if (result == null)
{ {
@ -30,21 +30,17 @@ namespace Emby.Server.Implementations.Services
{ {
httpResult.RequestContext = httpReq; httpResult.RequestContext = httpReq;
httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType; 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> /// <summary>
/// Writes to response. /// Writes to response.
/// Response headers are customizable by implementing IHasHeaders an returning Dictionary of Http headers. /// Response headers are customizable by implementing IHasHeaders an returning Dictionary of Http headers.
/// </summary> /// </summary>
/// <param name="response">The response.</param> private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request, CancellationToken cancellationToken)
/// <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)
{ {
var defaultContentType = request.ResponseContentType; var defaultContentType = request.ResponseContentType;
@ -105,7 +101,7 @@ namespace Emby.Server.Implementations.Services
var asyncStreamWriter = result as IAsyncStreamWriter; var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null) if (asyncStreamWriter != null)
{ {
await asyncStreamWriter.WriteToAsync(response.OutputStream, CancellationToken.None).ConfigureAwait(false); await asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken).ConfigureAwait(false);
return; return;
} }
@ -119,7 +115,7 @@ namespace Emby.Server.Implementations.Services
var fileWriter = result as FileWriter; var fileWriter = result as FileWriter;
if (fileWriter != null) if (fileWriter != null)
{ {
await fileWriter.WriteToAsync(response, CancellationToken.None).ConfigureAwait(false); await fileWriter.WriteToAsync(response, cancellationToken).ConfigureAwait(false);
return; return;
} }

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Services
// Set from SSHHF.GetHandlerForPathInfo() // Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; } 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); var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null) if (restPath == null)
@ -150,7 +151,7 @@ namespace Emby.Server.Implementations.Services
responseFilter(httpReq, httpRes, response); 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) public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, ILogger logger)

@ -174,14 +174,15 @@ namespace MediaBrowser.Api
return options; return options;
} }
protected MusicArtist GetArtist(string name, ILibraryManager libraryManager) protected MusicArtist GetArtist(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(MusicArtist).Name } IncludeItemTypes = new[] { typeof(MusicArtist).Name },
DtoOptions = dtoOptions
}).OfType<MusicArtist>().FirstOrDefault(); }).OfType<MusicArtist>().FirstOrDefault();
@ -191,17 +192,18 @@ namespace MediaBrowser.Api
} }
} }
return libraryManager.GetArtist(name); return libraryManager.GetArtist(name, dtoOptions);
} }
protected Studio GetStudio(string name, ILibraryManager libraryManager) protected Studio GetStudio(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(Studio).Name } IncludeItemTypes = new[] { typeof(Studio).Name },
DtoOptions = dtoOptions
}).OfType<Studio>().FirstOrDefault(); }).OfType<Studio>().FirstOrDefault();
@ -214,14 +216,15 @@ namespace MediaBrowser.Api
return libraryManager.GetStudio(name); return libraryManager.GetStudio(name);
} }
protected Genre GetGenre(string name, ILibraryManager libraryManager) protected Genre GetGenre(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(Genre).Name } IncludeItemTypes = new[] { typeof(Genre).Name },
DtoOptions = dtoOptions
}).OfType<Genre>().FirstOrDefault(); }).OfType<Genre>().FirstOrDefault();
@ -234,14 +237,15 @@ namespace MediaBrowser.Api
return libraryManager.GetGenre(name); return libraryManager.GetGenre(name);
} }
protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager) protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(MusicGenre).Name } IncludeItemTypes = new[] { typeof(MusicGenre).Name },
DtoOptions = dtoOptions
}).OfType<MusicGenre>().FirstOrDefault(); }).OfType<MusicGenre>().FirstOrDefault();
@ -254,14 +258,15 @@ namespace MediaBrowser.Api
return libraryManager.GetMusicGenre(name); return libraryManager.GetMusicGenre(name);
} }
protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager) protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(GameGenre).Name } IncludeItemTypes = new[] { typeof(GameGenre).Name },
DtoOptions = dtoOptions
}).OfType<GameGenre>().FirstOrDefault(); }).OfType<GameGenre>().FirstOrDefault();
@ -274,14 +279,15 @@ namespace MediaBrowser.Api
return libraryManager.GetGameGenre(name); return libraryManager.GetGameGenre(name);
} }
protected Person GetPerson(string name, ILibraryManager libraryManager) protected Person GetPerson(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{ {
if (name.IndexOf(BaseItem.SlugChar) != -1) if (name.IndexOf(BaseItem.SlugChar) != -1)
{ {
var result = libraryManager.GetItemList(new InternalItemsQuery var result = libraryManager.GetItemList(new InternalItemsQuery
{ {
SlugName = name, SlugName = name,
IncludeItemTypes = new[] { typeof(Person).Name } IncludeItemTypes = new[] { typeof(Person).Name },
DtoOptions = dtoOptions
}).OfType<Person>().FirstOrDefault(); }).OfType<Person>().FirstOrDefault();
@ -329,37 +335,33 @@ namespace MediaBrowser.Api
/// <summary> /// <summary>
/// Gets the name of the item by. /// Gets the name of the item by.
/// </summary> /// </summary>
/// <param name="name">The name.</param> protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager, DtoOptions dtoOptions)
/// <param name="type">The type.</param>
/// <param name="libraryManager">The library manager.</param>
/// <returns>Task{BaseItem}.</returns>
protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager)
{ {
BaseItem item; BaseItem item;
if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0) if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetPerson(name, libraryManager); item = GetPerson(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetArtist(name, libraryManager); item = GetArtist(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetGenre(name, libraryManager); item = GetGenre(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetMusicGenre(name, libraryManager); item = GetMusicGenre(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetGameGenre(name, libraryManager); item = GetGameGenre(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0)
{ {
item = GetStudio(name, libraryManager); item = GetStudio(name, libraryManager, dtoOptions);
} }
else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0) else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0)
{ {

@ -15,6 +15,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
@ -406,7 +407,7 @@ namespace MediaBrowser.Api.Images
{ {
var type = GetPathValue(0); var type = GetPathValue(0);
var item = GetItemByName(request.Name, type, _libraryManager); var item = GetItemByName(request.Name, type, _libraryManager, new DtoOptions(false));
return GetImage(request, item, false); return GetImage(request, item, false);
} }
@ -415,7 +416,7 @@ namespace MediaBrowser.Api.Images
{ {
var type = GetPathValue(0); var type = GetPathValue(0);
var item = GetItemByName(request.Name, type, _libraryManager); var item = GetItemByName(request.Name, type, _libraryManager, new DtoOptions(false));
return GetImage(request, item, true); return GetImage(request, item, true);
} }

@ -22,6 +22,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.LiveTv namespace MediaBrowser.Api.LiveTv
{ {
@ -698,8 +699,9 @@ namespace MediaBrowser.Api.LiveTv
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IAuthorizationContext _authContext; private readonly IAuthorizationContext _authContext;
private readonly ISessionContext _sessionContext; private readonly ISessionContext _sessionContext;
private readonly IEnvironmentInfo _environment;
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext) public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext, IEnvironmentInfo environment)
{ {
_liveTvManager = liveTvManager; _liveTvManager = liveTvManager;
_userManager = userManager; _userManager = userManager;
@ -710,6 +712,7 @@ namespace MediaBrowser.Api.LiveTv
_fileSystem = fileSystem; _fileSystem = fileSystem;
_authContext = authContext; _authContext = authContext;
_sessionContext = sessionContext; _sessionContext = sessionContext;
_environment = environment;
} }
public object Get(GetTunerHostTypes request) public object Get(GetTunerHostTypes request)
@ -731,7 +734,7 @@ namespace MediaBrowser.Api.LiveTv
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path); outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, CancellationToken.None) return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, _environment, CancellationToken.None)
{ {
AllowEndOfFile = false AllowEndOfFile = false
}; };
@ -750,7 +753,7 @@ namespace MediaBrowser.Api.LiveTv
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container); outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
return new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, CancellationToken.None) return new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, _environment, CancellationToken.None)
{ {
AllowEndOfFile = false AllowEndOfFile = false
}; };

@ -171,7 +171,7 @@ namespace MediaBrowser.Api.Music
public Task<object> Get(GetInstantMixFromArtist request) public Task<object> Get(GetInstantMixFromArtist request)
{ {
var user = _userManager.GetUserById(request.UserId); var user = _userManager.GetUserById(request.UserId);
var artist = _libraryManager.GetArtist(request.Name); var artist = _libraryManager.GetArtist(request.Name, new DtoOptions(false));
var dtoOptions = GetDtoOptions(_authContext, request); var dtoOptions = GetDtoOptions(_authContext, request);

@ -14,6 +14,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -35,6 +36,10 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated] //[Authenticated]
public class AudioService : BaseProgressiveStreamingService public class AudioService : BaseProgressiveStreamingService
{ {
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
{
}
/// <summary> /// <summary>
/// Gets the specified request. /// Gets the specified request.
/// </summary> /// </summary>
@ -61,9 +66,5 @@ namespace MediaBrowser.Api.Playback.Progressive
return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
} }
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor)
{
}
} }
} }

@ -16,6 +16,7 @@ using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -25,10 +26,12 @@ namespace MediaBrowser.Api.Playback.Progressive
public abstract class BaseProgressiveStreamingService : BaseStreamingService public abstract class BaseProgressiveStreamingService : BaseStreamingService
{ {
protected readonly IImageProcessor ImageProcessor; protected readonly IImageProcessor ImageProcessor;
protected readonly IEnvironmentInfo EnvironmentInfo;
public BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext) public BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
{ {
ImageProcessor = imageProcessor; ImageProcessor = imageProcessor;
EnvironmentInfo = environmentInfo;
} }
/// <summary> /// <summary>
@ -130,7 +133,7 @@ namespace MediaBrowser.Api.Playback.Progressive
// TODO: Don't hardcode this // TODO: Don't hardcode this
outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType("file.ts"); outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType("file.ts");
return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, CancellationToken.None) return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
{ {
AllowEndOfFile = false AllowEndOfFile = false
}; };
@ -174,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Progressive
outputHeaders["Content-Type"] = contentType; outputHeaders["Content-Type"] = contentType;
return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, CancellationToken.None) return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
{ {
AllowEndOfFile = false AllowEndOfFile = false
}; };
@ -398,7 +401,7 @@ namespace MediaBrowser.Api.Playback.Progressive
outputHeaders[item.Key] = item.Value; outputHeaders[item.Key] = item.Value;
} }
return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, CancellationToken.None); return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, EnvironmentInfo, CancellationToken.None);
} }
finally finally
{ {

@ -10,6 +10,7 @@ using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -22,16 +23,16 @@ namespace MediaBrowser.Api.Playback.Progressive
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
private readonly Dictionary<string, string> _outputHeaders; private readonly Dictionary<string, string> _outputHeaders;
// 256k const int StreamCopyToBufferSize = 81920;
private const int BufferSize = 81920;
private long _bytesWritten = 0; private long _bytesWritten = 0;
public long StartPosition { get; set; } public long StartPosition { get; set; }
public bool AllowEndOfFile = true; public bool AllowEndOfFile = true;
private readonly IDirectStreamProvider _directStreamProvider; private readonly IDirectStreamProvider _directStreamProvider;
private readonly IEnvironmentInfo _environment;
public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
_path = path; _path = path;
@ -39,15 +40,17 @@ namespace MediaBrowser.Api.Playback.Progressive
_job = job; _job = job;
_logger = logger; _logger = logger;
_cancellationToken = cancellationToken; _cancellationToken = cancellationToken;
_environment = environment;
} }
public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
{ {
_directStreamProvider = directStreamProvider; _directStreamProvider = directStreamProvider;
_outputHeaders = outputHeaders; _outputHeaders = outputHeaders;
_job = job; _job = job;
_logger = logger; _logger = logger;
_cancellationToken = cancellationToken; _cancellationToken = cancellationToken;
_environment = environment;
} }
public IDictionary<string, string> Headers public IDictionary<string, string> Headers
@ -58,33 +61,55 @@ namespace MediaBrowser.Api.Playback.Progressive
} }
} }
private Stream GetInputStream() private Stream GetInputStream(bool allowAsyncFileRead)
{ {
return _fileSystem.GetFileStream(_path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, true); var fileOpenOptions = StartPosition > 0
? FileOpenOptions.RandomAccess
: FileOpenOptions.SequentialScan;
if (allowAsyncFileRead)
{
fileOpenOptions |= FileOpenOptions.Asynchronous;
}
return _fileSystem.GetFileStream(_path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions);
} }
public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
{ {
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
try try
{ {
if (_directStreamProvider != null) if (_directStreamProvider != null)
{ {
await _directStreamProvider.CopyToAsync(outputStream, _cancellationToken).ConfigureAwait(false); await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
return; return;
} }
var eofCount = 0; var eofCount = 0;
using (var inputStream = GetInputStream()) // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows;
using (var inputStream = GetInputStream(allowAsyncFileRead))
{ {
if (StartPosition > 0) if (StartPosition > 0)
{ {
inputStream.Position = StartPosition; inputStream.Position = StartPosition;
} }
while (eofCount < 15 || !AllowEndOfFile) while (eofCount < 20 || !AllowEndOfFile)
{
int bytesRead;
if (allowAsyncFileRead)
{
bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
}
else
{ {
var bytesRead = await CopyToAsyncInternal(inputStream, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false); bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
}
//var position = fs.Position; //var position = fs.Position;
//_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
@ -95,7 +120,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{ {
eofCount++; eofCount++;
} }
await Task.Delay(100, _cancellationToken).ConfigureAwait(false); await Task.Delay(100, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
@ -113,15 +138,46 @@ namespace MediaBrowser.Api.Playback.Progressive
} }
} }
private async Task<int> CopyToAsyncInternal(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken) private async Task<int> CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken)
{
var array = new byte[StreamCopyToBufferSize];
int bytesRead;
int totalBytesRead = 0;
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{
var bytesToWrite = bytesRead;
if (bytesToWrite > 0)
{
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
_bytesWritten += bytesRead;
totalBytesRead += bytesRead;
if (_job != null)
{
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
}
}
}
return totalBytesRead;
}
private async Task<int> CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken)
{ {
byte[] buffer = new byte[bufferSize]; var array = new byte[StreamCopyToBufferSize];
int bytesRead; int bytesRead;
int totalBytesRead = 0; int totalBytesRead = 0;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
var bytesToWrite = bytesRead;
if (bytesToWrite > 0)
{ {
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
_bytesWritten += bytesRead; _bytesWritten += bytesRead;
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
@ -131,6 +187,7 @@ namespace MediaBrowser.Api.Playback.Progressive
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten); _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
} }
} }
}
return totalBytesRead; return totalBytesRead;
} }

@ -9,6 +9,7 @@ using MediaBrowser.Model.Serialization;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
{ {
@ -66,7 +67,7 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated] //[Authenticated]
public class VideoService : BaseProgressiveStreamingService public class VideoService : BaseProgressiveStreamingService
{ {
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor) public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
{ {
} }

@ -18,6 +18,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback namespace MediaBrowser.Api.Playback
{ {
@ -63,7 +64,7 @@ namespace MediaBrowser.Api.Playback
//[Authenticated] //[Authenticated]
public class UniversalAudioService : BaseApiService public class UniversalAudioService : BaseApiService
{ {
public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager) public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager, IEnvironmentInfo environmentInfo)
{ {
ServerConfigurationManager = serverConfigurationManager; ServerConfigurationManager = serverConfigurationManager;
UserManager = userManager; UserManager = userManager;
@ -80,6 +81,7 @@ namespace MediaBrowser.Api.Playback
AuthorizationContext = authorizationContext; AuthorizationContext = authorizationContext;
ImageProcessor = imageProcessor; ImageProcessor = imageProcessor;
NetworkManager = networkManager; NetworkManager = networkManager;
EnvironmentInfo = environmentInfo;
} }
protected IServerConfigurationManager ServerConfigurationManager { get; private set; } protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
@ -97,6 +99,7 @@ namespace MediaBrowser.Api.Playback
protected IAuthorizationContext AuthorizationContext { get; private set; } protected IAuthorizationContext AuthorizationContext { get; private set; }
protected IImageProcessor ImageProcessor { get; private set; } protected IImageProcessor ImageProcessor { get; private set; }
protected INetworkManager NetworkManager { get; private set; } protected INetworkManager NetworkManager { get; private set; }
protected IEnvironmentInfo EnvironmentInfo { get; private set; }
public Task<object> Get(GetUniversalAudioStream request) public Task<object> Get(GetUniversalAudioStream request)
{ {
@ -263,7 +266,8 @@ namespace MediaBrowser.Api.Playback
ZipClient, ZipClient,
JsonSerializer, JsonSerializer,
AuthorizationContext, AuthorizationContext,
ImageProcessor) ImageProcessor,
EnvironmentInfo)
{ {
Request = Request Request = Request
}; };

@ -68,10 +68,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetArtist request) private BaseItemDto GetItem(GetArtist request)
{ {
var item = GetArtist(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetArtist(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -267,7 +267,8 @@ namespace MediaBrowser.Api.UserLibrary
{ {
ExcludeItemTypes = excludeItemTypes, ExcludeItemTypes = excludeItemTypes,
IncludeItemTypes = includeItemTypes, IncludeItemTypes = includeItemTypes,
MediaTypes = mediaTypes MediaTypes = mediaTypes,
DtoOptions = dtoOptions
}; };
Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes); Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);

@ -56,10 +56,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetGameGenre request) private BaseItemDto GetItem(GetGameGenre request)
{ {
var item = GetGameGenre(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetGameGenre(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -66,10 +66,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetGenre request) private BaseItemDto GetItem(GetGenre request)
{ {
var item = GetGenre(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetGenre(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -358,7 +358,7 @@ namespace MediaBrowser.Api.UserLibrary
{ {
try try
{ {
return _libraryManager.GetArtist(i); return _libraryManager.GetArtist(i, new DtoOptions(false));
} }
catch catch
{ {

@ -57,10 +57,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetMusicGenre request) private BaseItemDto GetItem(GetMusicGenre request)
{ {
var item = GetMusicGenre(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetMusicGenre(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -64,10 +64,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetPerson request) private BaseItemDto GetItem(GetPerson request)
{ {
var item = GetPerson(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetPerson(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -66,10 +66,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns> /// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetStudio request) private BaseItemDto GetItem(GetStudio request)
{ {
var item = GetStudio(request.Name, LibraryManager);
var dtoOptions = GetDtoOptions(AuthorizationContext, request); var dtoOptions = GetDtoOptions(AuthorizationContext, request);
var item = GetStudio(request.Name, LibraryManager, dtoOptions);
if (!string.IsNullOrWhiteSpace(request.UserId)) if (!string.IsNullOrWhiteSpace(request.UserId))
{ {
var user = UserManager.GetUserById(request.UserId); var user = UserManager.GetUserById(request.UserId);

@ -8,6 +8,7 @@ using System.Linq;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
@ -42,7 +43,10 @@ namespace MediaBrowser.Controller.Entities.Audio
[IgnoreDataMember] [IgnoreDataMember]
public MusicArtist MusicArtist public MusicArtist MusicArtist
{ {
get get { return GetMusicArtist(new DtoOptions(true)); }
}
public MusicArtist GetMusicArtist(DtoOptions options)
{ {
var artist = GetParents().OfType<MusicArtist>().FirstOrDefault(); var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
@ -51,12 +55,11 @@ namespace MediaBrowser.Controller.Entities.Audio
var name = AlbumArtist; var name = AlbumArtist;
if (!string.IsNullOrWhiteSpace(name)) if (!string.IsNullOrWhiteSpace(name))
{ {
artist = LibraryManager.GetArtist(name); artist = LibraryManager.GetArtist(name, options);
} }
} }
return artist; return artist;
} }
}
[IgnoreDataMember] [IgnoreDataMember]
public override bool SupportsPlayedStatus public override bool SupportsPlayedStatus
@ -171,7 +174,7 @@ namespace MediaBrowser.Controller.Entities.Audio
id.AlbumArtists = AlbumArtists; id.AlbumArtists = AlbumArtists;
var artist = MusicArtist; var artist = GetMusicArtist(new DtoOptions(false));
if (artist != null) if (artist != null)
{ {

@ -160,42 +160,6 @@ namespace MediaBrowser.Controller.Entities
public DtoOptions DtoOptions { get; set; } public DtoOptions DtoOptions { get; set; }
public int MinSimilarityScore { get; set; } public int MinSimilarityScore { get; set; }
public bool HasField(ItemFields name)
{
var fields = 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:
return fields.Contains(name);
case ItemFields.ServiceName:
return true;
default:
return true;
}
}
public InternalItemsQuery() public InternalItemsQuery()
{ {
MinSimilarityScore = 20; MinSimilarityScore = 20;

@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO; using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
@ -68,18 +69,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <returns>Task{Artist}.</returns> /// <returns>Task{Artist}.</returns>
MusicArtist GetArtist(string name); MusicArtist GetArtist(string name);
/// <summary> MusicArtist GetArtist(string name, DtoOptions options);
/// Gets the album artists.
/// </summary>
/// <param name="items">The items.</param>
/// <returns>IEnumerable&lt;MusicArtist&gt;.</returns>
IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items);
/// <summary>
/// Gets the artists.
/// </summary>
/// <param name="items">The items.</param>
/// <returns>IEnumerable&lt;MusicArtist&gt;.</returns>
IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items);
/// <summary> /// <summary>
/// Gets a Studio /// Gets a Studio
/// </summary> /// </summary>

@ -1,8 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
@ -10,7 +13,8 @@ namespace MediaBrowser.Controller.LiveTv
{ {
public MediaSourceInfo OriginalMediaSource { get; set; } public MediaSourceInfo OriginalMediaSource { get; set; }
public MediaSourceInfo OpenedMediaSource { get; set; } public MediaSourceInfo OpenedMediaSource { get; set; }
public int ConsumerCount { public int ConsumerCount
{
get { return SharedStreamIds.Count; } get { return SharedStreamIds.Count; }
} }
public ITunerHost TunerHost { get; set; } public ITunerHost TunerHost { get; set; }
@ -19,10 +23,15 @@ namespace MediaBrowser.Controller.LiveTv
public string UniqueId = Guid.NewGuid().ToString("N"); public string UniqueId = Guid.NewGuid().ToString("N");
public List<string> SharedStreamIds = new List<string>(); public List<string> SharedStreamIds = new List<string>();
protected readonly IEnvironmentInfo Environment;
protected readonly IFileSystem FileSystem;
const int StreamCopyToBufferSize = 81920;
public LiveStream(MediaSourceInfo mediaSource) public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem)
{ {
OriginalMediaSource = mediaSource; OriginalMediaSource = mediaSource;
Environment = environment;
FileSystem = fileSystem;
OpenedMediaSource = mediaSource; OpenedMediaSource = mediaSource;
EnableStreamSharing = true; EnableStreamSharing = true;
} }
@ -41,5 +50,131 @@ namespace MediaBrowser.Controller.LiveTv
{ {
return Task.FromResult(true); return Task.FromResult(true);
} }
private Stream GetInputStream(string path, long startPosition, bool allowAsyncFileRead)
{
var fileOpenOptions = startPosition > 0
? FileOpenOptions.RandomAccess
: FileOpenOptions.SequentialScan;
if (allowAsyncFileRead)
{
fileOpenOptions |= FileOpenOptions.Asynchronous;
}
return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions);
}
protected async Task DeleteTempFile(string path, int retryCount = 0)
{
try
{
FileSystem.DeleteFile(path);
return;
}
catch
{
}
if (retryCount > 20)
{
return;
}
await Task.Delay(500).ConfigureAwait(false);
await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false);
}
protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken)
{
var eofCount = 0;
long startPosition = -25000;
if (startPosition < 0)
{
var length = FileSystem.GetFileInfo(path).Length;
startPosition = Math.Max(length - startPosition, 0);
}
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
var allowAsyncFileRead = Environment.OperatingSystem != OperatingSystem.Windows;
using (var inputStream = GetInputStream(path, startPosition, allowAsyncFileRead))
{
if (startPosition > 0)
{
inputStream.Position = startPosition;
}
while (eofCount < 20 || !allowEndOfFile)
{
int bytesRead;
if (allowAsyncFileRead)
{
bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
}
else
{
bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
}
//var position = fs.Position;
//_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
if (bytesRead == 0)
{
eofCount++;
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
else
{
eofCount = 0;
}
}
}
}
private async Task<int> CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken)
{
var array = new byte[StreamCopyToBufferSize];
int bytesRead;
int totalBytesRead = 0;
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{
var bytesToWrite = bytesRead;
if (bytesToWrite > 0)
{
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
}
}
return totalBytesRead;
}
private async Task<int> CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken)
{
var array = new byte[StreamCopyToBufferSize];
int bytesRead;
int totalBytesRead = 0;
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
var bytesToWrite = bytesRead;
if (bytesToWrite > 0)
{
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
}
}
return totalBytesRead;
}
} }
} }

@ -235,6 +235,9 @@
ExternalEtag, ExternalEtag,
PresentationUniqueKey, PresentationUniqueKey,
InheritedParentalRatingValue, InheritedParentalRatingValue,
ExternalSeriesId ExternalSeriesId,
SeriesPresentationUniqueKey,
DateLastRefreshed,
DateLastSaved
} }
} }

@ -305,8 +305,6 @@ namespace MediaBrowser.WebDashboard.Api
} }
} }
path = path.Replace("scripts/jquery.mobile-1.4.5.min.map", "thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.map", StringComparison.OrdinalIgnoreCase);
var localizationCulture = GetLocalizationCulture(); var localizationCulture = GetLocalizationCulture();
// Don't cache if not configured to do so // Don't cache if not configured to do so
@ -330,9 +328,15 @@ namespace MediaBrowser.WebDashboard.Api
var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5(); var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5();
// html gets modified on the fly
if (contentType.StartsWith("text/html", StringComparison.OrdinalIgnoreCase))
{
return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(basePath, path, localizationCulture)).ConfigureAwait(false); return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(basePath, path, localizationCulture)).ConfigureAwait(false);
} }
return await _resultFactory.GetStaticFileResult(Request, GetPackageCreator(basePath).GetResourcePath(path));
}
private string GetLocalizationCulture() private string GetLocalizationCulture()
{ {
return _serverConfigurationManager.Configuration.UICulture; return _serverConfigurationManager.Configuration.UICulture;

@ -68,7 +68,7 @@ namespace MediaBrowser.WebDashboard.Api
/// Gets the dashboard resource path. /// Gets the dashboard resource path.
/// </summary> /// </summary>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private string GetDashboardResourcePath(string virtualPath) public string GetResourcePath(string virtualPath)
{ {
var fullPath = Path.Combine(_basePath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar)); var fullPath = Path.Combine(_basePath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar));
@ -97,7 +97,7 @@ namespace MediaBrowser.WebDashboard.Api
return false; return false;
} }
path = GetDashboardResourcePath(path); path = GetResourcePath(path);
var parent = _fileSystem.GetDirectoryName(path); var parent = _fileSystem.GetDirectoryName(path);
return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) || return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) ||
@ -140,7 +140,7 @@ namespace MediaBrowser.WebDashboard.Api
html = html.Substring(0, index); html = html.Substring(0, index);
} }
} }
var mainFile = _fileSystem.ReadAllText(GetDashboardResourcePath("index.html")); var mainFile = _fileSystem.ReadAllText(GetResourcePath("index.html"));
html = ReplaceFirst(mainFile, "<div class=\"mainAnimatedPages skinBody\"></div>", "<div class=\"mainAnimatedPages skinBody hide\">" + html + "</div>"); html = ReplaceFirst(mainFile, "<div class=\"mainAnimatedPages skinBody\"></div>", "<div class=\"mainAnimatedPages skinBody hide\">" + html + "</div>");
} }
@ -299,7 +299,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary> /// </summary>
private Stream GetRawResourceStream(string virtualPath) private Stream GetRawResourceStream(string virtualPath)
{ {
return _fileSystem.GetFileStream(GetDashboardResourcePath(virtualPath), FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, true); return _fileSystem.GetFileStream(GetResourcePath(virtualPath), FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, true);
} }
} }

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.17.9")] [assembly: AssemblyVersion("3.2.17.10")]

@ -148,6 +148,7 @@ namespace SocketHttpListener.Net
} }
const int MsCopyBufferSize = 81920; const int MsCopyBufferSize = 81920;
const int StreamCopyToBufferSize = 81920;
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
if (disposed) if (disposed)
@ -340,11 +341,11 @@ namespace SocketHttpListener.Net
{ {
if (allowAsync) if (allowAsync)
{ {
await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false); await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
fs.CopyTo(targetStream, 81920); fs.CopyTo(targetStream, StreamCopyToBufferSize);
} }
} }
} }
@ -352,16 +353,11 @@ namespace SocketHttpListener.Net
private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{ {
var array = new byte[81920]; var array = new byte[StreamCopyToBufferSize];
int bytesRead; int bytesRead;
while ((bytesRead = source.Read(array, 0, array.Length)) != 0) while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{ {
if (bytesRead == 0)
{
break;
}
var bytesToWrite = Math.Min(bytesRead, copyLength); var bytesToWrite = Math.Min(bytesRead, copyLength);
if (bytesToWrite > 0) if (bytesToWrite > 0)
@ -380,16 +376,11 @@ namespace SocketHttpListener.Net
private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{ {
var array = new byte[81920]; var array = new byte[StreamCopyToBufferSize];
int bytesRead; int bytesRead;
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{ {
if (bytesRead == 0)
{
break;
}
var bytesToWrite = Math.Min(bytesRead, copyLength); var bytesToWrite = Math.Min(bytesRead, copyLength);
if (bytesToWrite > 0) if (bytesToWrite > 0)

Loading…
Cancel
Save