aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2017-05-22 00:54:02 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2017-05-22 00:54:02 -0400
commit54cf0da75826d641b28a34afece7a4cb0eaaaec2 (patch)
tree8d6f313fe9d71a5ecaf7a235eff4c5db6e68990b
parent41ea0d99f4ee953d6e955c355cef0e5088f9b9fd (diff)
update query fields
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs254
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs12
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs8
-rw-r--r--Emby.Server.Implementations/HttpServer/IHttpListener.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs9
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs71
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs42
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs15
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs55
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs7
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs16
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs5
-rw-r--r--MediaBrowser.Api/BaseApiService.cs50
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs5
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs9
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs9
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs11
-rw-r--r--MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs95
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs3
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs8
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs4
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs3
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs4
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs4
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs6
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs25
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs36
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs14
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveStream.cs141
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs5
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs10
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs8
-rw-r--r--SharedVersion.cs2
-rw-r--r--SocketHttpListener.Portable/Net/ResponseStream.cs19
41 files changed, 620 insertions, 385 deletions
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 49bf9e39c..fbd97b6a2 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -1415,66 +1415,69 @@ namespace Emby.Server.Implementations.Data
var index = 5;
- var hasProgramAttributes = item as IHasProgramAttributes;
- if (hasProgramAttributes != null)
+ if (HasProgramAttributes(query))
{
- if (!reader.IsDBNull(index))
+ var hasProgramAttributes = item as IHasProgramAttributes;
+ if (hasProgramAttributes != null)
{
- hasProgramAttributes.IsMovie = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsMovie = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsSports = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsSports = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsKids = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsKids = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsSeries = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsSeries = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsLive = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsLive = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsNews = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsNews = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
- {
- hasProgramAttributes.EpisodeTitle = reader.GetString(index);
- }
- index++;
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.EpisodeTitle = reader.GetString(index);
+ }
+ index++;
- if (!reader.IsDBNull(index))
+ if (!reader.IsDBNull(index))
+ {
+ hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
+ }
+ index++;
+ }
+ else
{
- hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
+ index += 9;
}
- index++;
- }
- else
- {
- index += 9;
}
if (!reader.IsDBNull(index))
@@ -1483,7 +1486,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.CustomRating))
+ if (HasField(query, ItemFields.CustomRating))
{
if (!reader.IsDBNull(index))
{
@@ -1498,7 +1501,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.Settings))
+ if (HasField(query, ItemFields.Settings))
{
if (!reader.IsDBNull(index))
{
@@ -1525,7 +1528,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.ExternalEtag))
+ if (HasField(query, ItemFields.ExternalEtag))
{
if (!reader.IsDBNull(index))
{
@@ -1534,11 +1537,14 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.DateLastRefreshed))
{
- item.DateLastRefreshed = reader[index].ReadDateTime();
+ if (!reader.IsDBNull(index))
+ {
+ item.DateLastRefreshed = reader[index].ReadDateTime();
+ }
+ index++;
}
- index++;
if (!reader.IsDBNull(index))
{
@@ -1558,7 +1564,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.Overview))
+ if (HasField(query, ItemFields.Overview))
{
if (!reader.IsDBNull(index))
{
@@ -1585,7 +1591,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.HomePageUrl))
+ if (HasField(query, ItemFields.HomePageUrl))
{
if (!reader.IsDBNull(index))
{
@@ -1594,7 +1600,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.DisplayMediaType))
+ if (HasField(query, ItemFields.DisplayMediaType))
{
if (!reader.IsDBNull(index))
{
@@ -1603,7 +1609,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.SortName))
+ if (HasField(query, ItemFields.SortName))
{
if (!reader.IsDBNull(index))
{
@@ -1618,7 +1624,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.VoteCount))
+ if (HasField(query, ItemFields.VoteCount))
{
if (!reader.IsDBNull(index))
{
@@ -1627,7 +1633,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.DateCreated))
+ if (HasField(query, ItemFields.DateCreated))
{
if (!reader.IsDBNull(index))
{
@@ -1645,7 +1651,7 @@ namespace Emby.Server.Implementations.Data
item.Id = reader.GetGuid(index);
index++;
- if (query.HasField(ItemFields.Genres))
+ if (HasField(query, ItemFields.Genres))
{
if (!reader.IsDBNull(index))
{
@@ -1680,13 +1686,16 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.DateLastSaved))
{
- item.DateLastSaved = reader[index].ReadDateTime();
+ if (!reader.IsDBNull(index))
+ {
+ item.DateLastSaved = reader[index].ReadDateTime();
+ }
+ index++;
}
- index++;
- if (query.HasField(ItemFields.Settings))
+ if (HasField(query, ItemFields.Settings))
{
if (!reader.IsDBNull(index))
{
@@ -1695,7 +1704,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Studios))
+ if (HasField(query, ItemFields.Studios))
{
if (!reader.IsDBNull(index))
{
@@ -1704,7 +1713,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Tags))
+ if (HasField(query, ItemFields.Tags))
{
if (!reader.IsDBNull(index))
{
@@ -1729,7 +1738,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.OriginalTitle))
+ if (HasField(query, ItemFields.OriginalTitle))
{
if (!reader.IsDBNull(index))
{
@@ -1748,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.DateLastMediaAdded))
+ if (HasField(query, ItemFields.DateLastMediaAdded))
{
var folder = item as Folder;
if (folder != null && !reader.IsDBNull(index))
@@ -1814,7 +1823,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.PresentationUniqueKey))
+ if (HasField(query, ItemFields.PresentationUniqueKey))
{
if (!reader.IsDBNull(index))
{
@@ -1823,7 +1832,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.InheritedParentalRatingValue))
+ if (HasField(query, ItemFields.InheritedParentalRatingValue))
{
if (!reader.IsDBNull(index))
{
@@ -1832,7 +1841,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Tags))
+ if (HasField(query, ItemFields.Tags))
{
if (!reader.IsDBNull(index))
{
@@ -1841,7 +1850,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ExternalSeriesId))
+ if (HasField(query, ItemFields.ExternalSeriesId))
{
if (!reader.IsDBNull(index))
{
@@ -1850,7 +1859,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Taglines))
+ if (HasField(query, ItemFields.Taglines))
{
if (!reader.IsDBNull(index))
{
@@ -1859,7 +1868,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Keywords))
+ if (HasField(query, ItemFields.Keywords))
{
if (!reader.IsDBNull(index))
{
@@ -1883,7 +1892,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ProductionLocations))
+ if (HasField(query, ItemFields.ProductionLocations))
{
if (!reader.IsDBNull(index))
{
@@ -1892,7 +1901,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ThemeSongIds))
+ if (HasField(query, ItemFields.ThemeSongIds))
{
if (!reader.IsDBNull(index))
{
@@ -1901,7 +1910,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ThemeVideoIds))
+ if (HasField(query, ItemFields.ThemeVideoIds))
{
if (!reader.IsDBNull(index))
{
@@ -1942,14 +1951,17 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (hasSeries != null)
+ if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
{
- if (!reader.IsDBNull(index))
+ if (hasSeries != null)
{
- hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
+ }
}
+ index++;
}
- index++;
return item;
}
@@ -2259,13 +2271,73 @@ namespace Emby.Server.Implementations.Data
return new[] { field.ToString() };
}
+ private bool HasField(InternalItemsQuery query, ItemFields name)
+ {
+ var fields = query.DtoOptions.Fields;
+
+ switch (name)
+ {
+ case ItemFields.HomePageUrl:
+ case ItemFields.Keywords:
+ case ItemFields.DisplayMediaType:
+ case ItemFields.VoteCount:
+ case ItemFields.CustomRating:
+ case ItemFields.ProductionLocations:
+ case ItemFields.Settings:
+ case ItemFields.OriginalTitle:
+ case ItemFields.Taglines:
+ case ItemFields.SortName:
+ case ItemFields.Studios:
+ case ItemFields.Tags:
+ case ItemFields.ThemeSongIds:
+ case ItemFields.ThemeVideoIds:
+ case ItemFields.DateCreated:
+ case ItemFields.Overview:
+ case ItemFields.Genres:
+ case ItemFields.DateLastMediaAdded:
+ case ItemFields.ExternalEtag:
+ case ItemFields.PresentationUniqueKey:
+ case ItemFields.InheritedParentalRatingValue:
+ case ItemFields.ExternalSeriesId:
+ case ItemFields.SeriesPresentationUniqueKey:
+ case ItemFields.DateLastRefreshed:
+ case ItemFields.DateLastSaved:
+ return fields.Contains(name);
+ case ItemFields.ServiceName:
+ return true;
+ default:
+ return true;
+ }
+ }
+
+ private bool HasProgramAttributes(InternalItemsQuery query)
+ {
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Program",
+ "Recording",
+ "TvChannel",
+ "LiveTvAudioRecording",
+ "LiveTvVideoRecording",
+ "LiveTvProgram",
+ "LiveTvTvChannel"
+ };
+
+ return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
+ }
+
private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
{
var list = startColumns.ToList();
foreach (var field in allFields)
{
- if (!query.HasField(field))
+ if (!HasField(query, field))
{
foreach (var fieldToRemove in GetColumnNamesFromField(field).ToList())
{
@@ -2274,6 +2346,19 @@ namespace Emby.Server.Implementations.Data
}
}
+ if (!HasProgramAttributes(query))
+ {
+ list.Remove("IsKids");
+ list.Remove("IsMovie");
+ list.Remove("IsSports");
+ list.Remove("IsSeries");
+ list.Remove("IsLive");
+ list.Remove("IsNews");
+ list.Remove("IsPremiere");
+ list.Remove("EpisodeTitle");
+ list.Remove("IsRepeat");
+ }
+
if (!query.DtoOptions.EnableImages)
{
list.Remove("Images");
@@ -2400,7 +2485,7 @@ namespace Emby.Server.Implementations.Data
query.Limit = query.Limit.Value + 4;
}
- var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new [] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
+ var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
commandText += GetJoinUserDataText(query);
var whereClauses = GetWhereClauses(query, null);
@@ -3671,6 +3756,7 @@ namespace Emby.Server.Implementations.Data
if (!string.IsNullOrWhiteSpace(query.SlugName))
{
+ Logger.Info("Searching by SlugName for {0}", query.SlugName);
whereClauses.Add("CleanName=@SlugName");
if (statement != null)
{
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index bb46e6006..6f2e437cf 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1137,7 +1137,10 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var artist = _libraryManager.GetArtist(i);
+ var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
+ {
+ EnableImages = false
+ });
if (artist != null)
{
return new NameIdPair
@@ -1186,7 +1189,10 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var artist = _libraryManager.GetArtist(i);
+ var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
+ {
+ EnableImages = false
+ });
if (artist != null)
{
return new NameIdPair
@@ -1456,7 +1462,7 @@ namespace Emby.Server.Implementations.Dto
var musicAlbum = item as MusicAlbum;
if (musicAlbum != null)
{
- var artist = musicAlbum.MusicArtist;
+ var artist = musicAlbum.GetMusicArtist(new DtoOptions(false));
if (artist != null)
{
return artist;
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 5e96eda94..79209d438 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
@@ -445,10 +446,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
- /// <param name="httpReq">The HTTP req.</param>
- /// <param name="url">The URL.</param>
- /// <returns>Task.</returns>
- protected async Task RequestHandler(IHttpRequest httpReq, Uri url)
+ protected async Task RequestHandler(IHttpRequest httpReq, Uri url, CancellationToken cancellationToken)
{
var date = DateTime.Now;
var httpRes = httpReq.Response;
@@ -589,7 +587,7 @@ namespace Emby.Server.Implementations.HttpServer
if (handler != null)
{
- await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName).ConfigureAwait(false);
+ await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName, cancellationToken).ConfigureAwait(false);
}
else
{
diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
index 18df5682d..82175dbed 100644
--- a/Emby.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Net;
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
@@ -18,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer
/// Gets or sets the request handler.
/// </summary>
/// <value>The request handler.</value>
- Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
+ Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
/// <summary>
/// Gets or sets the web socket handler.
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index 682fa7a0b..f085ff71e 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -4,6 +4,7 @@ using SocketHttpListener.Net;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Cryptography;
@@ -50,7 +51,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
}
public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
- public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
+ public Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
@@ -82,10 +83,10 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private void ProcessContext(HttpListenerContext context)
{
//Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness);
- Task.Run(() => InitTask(context));
+ Task.Run(() => InitTask(context, CancellationToken.None));
}
- private Task InitTask(HttpListenerContext context)
+ private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
{
IHttpRequest httpReq = null;
var request = context.Request;
@@ -111,7 +112,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return Task.FromResult(true);
}
- return RequestHandler(httpReq, request.Url);
+ return RequestHandler(httpReq, request.Url, cancellationToken);
}
private void ProcessWebSocketRequest(HttpListenerContext ctx)
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index a423db9d6..8907c911a 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -885,7 +885,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Person}.</returns>
public Person GetPerson(string name)
{
- return CreateItemByName<Person>(Person.GetPath, name);
+ return CreateItemByName<Person>(Person.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -895,7 +895,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Studio}.</returns>
public Studio GetStudio(string name)
{
- return CreateItemByName<Studio>(Studio.GetPath, name);
+ return CreateItemByName<Studio>(Studio.GetPath, name, new DtoOptions(true));
}
public Guid GetStudioId(string name)
@@ -925,7 +925,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public Genre GetGenre(string name)
{
- return CreateItemByName<Genre>(Genre.GetPath, name);
+ return CreateItemByName<Genre>(Genre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -935,7 +935,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{MusicGenre}.</returns>
public MusicGenre GetMusicGenre(string name)
{
- return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name);
+ return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -945,7 +945,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{GameGenre}.</returns>
public GameGenre GetGameGenre(string name)
{
- return CreateItemByName<GameGenre>(GameGenre.GetPath, name);
+ return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Library
var name = value.ToString(CultureInfo.InvariantCulture);
- return CreateItemByName<Year>(Year.GetPath, name);
+ return CreateItemByName<Year>(Year.GetPath, name, new DtoOptions(true));
}
/// <summary>
@@ -973,10 +973,15 @@ namespace Emby.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public MusicArtist GetArtist(string name)
{
- return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name);
+ return GetArtist(name, new DtoOptions(true));
}
- private T CreateItemByName<T>(Func<string, string> getPathFn, string name)
+ public MusicArtist GetArtist(string name, DtoOptions options)
+ {
+ return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name, options);
+ }
+
+ private T CreateItemByName<T>(Func<string, string> getPathFn, string name, DtoOptions options)
where T : BaseItem, new()
{
if (typeof(T) == typeof(MusicArtist))
@@ -985,7 +990,7 @@ namespace Emby.Server.Implementations.Library
{
IncludeItemTypes = new[] { typeof(T).Name },
Name = name,
- DtoOptions = new DtoOptions(true)
+ DtoOptions = options
}).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
@@ -1029,54 +1034,6 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
- public IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items)
- {
- var names = items
- .SelectMany(i => i.AlbumArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
- public IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items)
- {
- var names = items
- .SelectMany(i => i.AllArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
/// <summary>
/// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation.
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 89b772731..83db58668 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1234,8 +1234,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
BufferMs = 0,
IgnoreDts = true,
- IgnoreIndex = true,
- GenPtsInput = true
+ IgnoreIndex = true
};
var isAudio = false;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index fa505d3fb..48ad7cf12 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -479,7 +479,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!(service is EmbyTV.EmbyTV))
{
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
- mediaSource.SupportsDirectPlay = false;
+ //mediaSource.SupportsDirectPlay = false;
mediaSource.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 5d489985f..c1e1bf2b6 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -422,8 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true,
IsInfiniteStream = true,
IgnoreDts = true,
- IgnoreIndex = true,
- GenPtsInput = true
+ IgnoreIndex = true
};
mediaSource.InferTotalBitrate();
@@ -507,12 +506,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{
- return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+ return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
// The UDP method is not working reliably on OSX, and on BSD it hasn't been tested yet
- var enableHttpStream = _environment.OperatingSystem == OperatingSystem.OSX ||
- _environment.OperatingSystem == OperatingSystem.BSD;
+ var enableHttpStream = _environment.OperatingSystem == OperatingSystem.OSX
+ || _environment.OperatingSystem == OperatingSystem.BSD;
enableHttpStream = true;
if (enableHttpStream)
{
@@ -521,17 +520,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var httpUrl = GetApiUrl(info, true) + "/auto/v" + hdhrId;
// If raw was used, the tuner doesn't support params
- if (!string.IsNullOrWhiteSpace(profile)
- && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
{
httpUrl += "?transcode=" + profile;
}
mediaSource.Path = httpUrl;
- return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
+ return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
}
- return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+ return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);
}
public async Task Validate(TunerHostInfo info)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
index dd63bbb72..03c21b120 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
@@ -17,24 +18,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
- private readonly MulticastStream _multicastStream;
- public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
- : base(mediaSource)
+ private readonly string _tempFilePath;
+
+ public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment)
+ : base(mediaSource, environment, fileSystem)
{
- _fileSystem = fileSystem;
_httpClient = httpClient;
_logger = logger;
- _appPaths = appPaths;
_appHost = appHost;
OriginalStreamId = originalStreamId;
- _multicastStream = new MulticastStream(_logger);
+
+ _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
}
protected override async Task OpenInternal(CancellationToken openCancellationToken)
@@ -74,9 +73,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task;
}
- private async Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+ private Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
- await Task.Run(async () =>
+ return Task.Run(async () =>
{
var isFirstAttempt = true;
@@ -101,13 +100,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
_logger.Info("Beginning multicastStream.CopyUntilCancelled");
- Action onStarted = null;
- if (isFirstAttempt)
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
+ using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.Asynchronous | FileOpenOptions.SequentialScan))
{
- onStarted = () => openTaskCompletionSource.TrySetResult(true);
- }
+ ResolveAfterDelay(2000, openTaskCompletionSource);
- await _multicastStream.CopyUntilCancelled(response.Content, onStarted, cancellationToken).ConfigureAwait(false);
+ await response.Content.CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false);
+ }
}
}
}
@@ -131,13 +130,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
_liveStreamTaskCompletionSource.TrySetResult(true);
+ await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
+ });
+ }
- }).ConfigureAwait(false);
+ private void ResolveAfterDelay(int delayMs, TaskCompletionSource<bool> openTaskCompletionSource)
+ {
+ Task.Run(async () =>
+ {
+ await Task.Delay(delayMs).ConfigureAwait(false);
+ openTaskCompletionSource.TrySetResult(true);
+ });
}
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- return _multicastStream.CopyToAsync(stream , cancellationToken);
+ return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 2c678d9f8..3202b7313 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -46,10 +46,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class HdHomerunChannelCommands : IHdHomerunChannelCommands
{
private string _channel;
+ private string _profile;
- public HdHomerunChannelCommands(string channel)
+ public HdHomerunChannelCommands(string channel, string profile)
{
_channel = channel;
+ _profile = profile;
}
public IEnumerable<Tuple<string, string>> GetCommands()
@@ -57,7 +59,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var commands = new List<Tuple<string, string>>();
if (!String.IsNullOrEmpty(_channel))
- commands.Add(Tuple.Create("vchannel", _channel));
+ {
+ if (!string.IsNullOrWhiteSpace(_profile) && !string.Equals(_profile, "native", StringComparison.OrdinalIgnoreCase))
+ {
+ commands.Add(Tuple.Create("vchannel", String.Format("{0} transcode={1}", _channel, _profile)));
+ }
+ else
+ {
+ commands.Add(Tuple.Create("vchannel", _channel));
+ }
+ }
return commands;
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index c84aebce7..ff6c0fb2c 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -14,39 +14,35 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider
{
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationPaths _appPaths;
private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory;
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
- private readonly MulticastStream _multicastStream;
private readonly IHdHomerunChannelCommands _channelCommands;
private readonly int _numTuners;
private readonly INetworkManager _networkManager;
- public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager)
- : base(mediaSource)
+ private readonly string _tempFilePath;
+
+ public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment)
+ : base(mediaSource, environment, fileSystem)
{
- _fileSystem = fileSystem;
- _httpClient = httpClient;
_logger = logger;
- _appPaths = appPaths;
_appHost = appHost;
_socketFactory = socketFactory;
_networkManager = networkManager;
OriginalStreamId = originalStreamId;
- _multicastStream = new MulticastStream(_logger);
_channelCommands = channelCommands;
_numTuners = numTuners;
+ _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts");
}
protected override async Task OpenInternal(CancellationToken openCancellationToken)
@@ -87,9 +83,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _liveStreamTaskCompletionSource.Task;
}
- private async Task StartStreaming(string remoteIp, int localPort, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+ private Task StartStreaming(string remoteIp, int localPort, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
- await Task.Run(async () =>
+ return Task.Run(async () =>
{
var isFirstAttempt = true;
using (var udpClient = _socketFactory.CreateUdpSocket(localPort))
@@ -124,13 +120,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (!cancellationToken.IsCancellationRequested)
{
- Action onStarted = null;
- if (isFirstAttempt)
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath));
+ using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.Asynchronous | FileOpenOptions.SequentialScan))
{
- onStarted = () => openTaskCompletionSource.TrySetResult(true);
- }
+ ResolveAfterDelay(2000, openTaskCompletionSource);
- await _multicastStream.CopyUntilCancelled(new UdpClientStream(udpClient), onStarted, cancellationToken).ConfigureAwait(false);
+ await new UdpClientStream(udpClient).CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false);
+ }
}
}
catch (OperationCanceledException ex)
@@ -159,12 +155,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- }).ConfigureAwait(false);
+ await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
+ });
+ }
+
+ private void ResolveAfterDelay(int delayMs, TaskCompletionSource<bool> openTaskCompletionSource)
+ {
+ Task.Run(async () =>
+ {
+ await Task.Delay(delayMs).ConfigureAwait(false);
+ openTaskCompletionSource.TrySetResult(true);
+ });
}
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- return _multicastStream.CopyToAsync(stream, cancellationToken);
+ return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
}
}
@@ -198,7 +204,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// This will always receive a 1328 packet size (PacketSize + RtpHeaderSize)
// The RTP header will be stripped so see how many reads we need to make to fill the buffer.
- int numReads = count / PacketSize;
+ var numReads = count / PacketSize;
+
int totalBytesRead = 0;
for (int i = 0; i < numReads; ++i)
@@ -206,7 +213,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var data = await _udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
-
+
// remove rtp header
Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, buffer, offset, bytesRead);
offset += bytesRead;
@@ -224,7 +231,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
- throw new NotImplementedException();
+ return true;
}
}
@@ -232,7 +239,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
- throw new NotImplementedException();
+ return false;
}
}
@@ -240,7 +247,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
get
{
- throw new NotImplementedException();
+ return false;
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 8cf1106f0..2c6641ee1 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -19,6 +19,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
@@ -27,13 +28,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
+ private readonly IEnvironmentInfo _environment;
- public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
+ public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment)
: base(config, logger, jsonSerializer, mediaEncoder)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_appHost = appHost;
+ _environment = environment;
}
public override string Type
@@ -73,7 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
- var liveStream = new LiveStream(sources.First());
+ var liveStream = new LiveStream(sources.First(), _environment, _fileSystem);
return liveStream;
}
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 3c2af60db..22d2b95f7 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Services
{
public static class ResponseHelper
{
- public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result)
+ public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result, CancellationToken cancellationToken)
{
if (result == null)
{
@@ -30,21 +30,17 @@ namespace Emby.Server.Implementations.Services
{
httpResult.RequestContext = httpReq;
httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType;
- return WriteToResponseInternal(httpRes, httpResult, httpReq);
+ return WriteToResponseInternal(httpRes, httpResult, httpReq, cancellationToken);
}
- return WriteToResponseInternal(httpRes, result, httpReq);
+ return WriteToResponseInternal(httpRes, result, httpReq, cancellationToken);
}
/// <summary>
/// Writes to response.
/// Response headers are customizable by implementing IHasHeaders an returning Dictionary of Http headers.
/// </summary>
- /// <param name="response">The response.</param>
- /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
- /// <param name="request">The serialization context.</param>
- /// <returns></returns>
- private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request)
+ private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request, CancellationToken cancellationToken)
{
var defaultContentType = request.ResponseContentType;
@@ -105,7 +101,7 @@ namespace Emby.Server.Implementations.Services
var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null)
{
- await asyncStreamWriter.WriteToAsync(response.OutputStream, CancellationToken.None).ConfigureAwait(false);
+ await asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken).ConfigureAwait(false);
return;
}
@@ -119,7 +115,7 @@ namespace Emby.Server.Implementations.Services
var fileWriter = result as FileWriter;
if (fileWriter != null)
{
- await fileWriter.WriteToAsync(response, CancellationToken.None).ConfigureAwait(false);
+ await fileWriter.WriteToAsync(response, cancellationToken).ConfigureAwait(false);
return;
}
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index 8b59b4843..95a9dd682 100644
--- a/Emby.Server.Implementations/Services/ServiceHandler.cs
+++ b/Emby.Server.Implementations/Services/ServiceHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Logging;
@@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Services
// Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; }
- public async Task ProcessRequestAsync(HttpListenerHost appHost, IRequest httpReq, IResponse httpRes, ILogger logger, string operationName)
+ public async Task ProcessRequestAsync(HttpListenerHost appHost, IRequest httpReq, IResponse httpRes, ILogger logger, string operationName, CancellationToken cancellationToken)
{
var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null)
@@ -150,7 +151,7 @@ namespace Emby.Server.Implementations.Services
responseFilter(httpReq, httpRes, response);
}
- await ResponseHelper.WriteToResponse(httpRes, httpReq, response).ConfigureAwait(false);
+ await ResponseHelper.WriteToResponse(httpRes, httpReq, response, cancellationToken).ConfigureAwait(false);
}
public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, ILogger logger)
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 1a57ff62d..0f1d240d0 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -174,14 +174,15 @@ namespace MediaBrowser.Api
return options;
}
- protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
+ protected MusicArtist GetArtist(string name, ILibraryManager libraryManager, DtoOptions dtoOptions)
{
if (name.IndexOf(BaseItem.SlugChar) != -1)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(MusicArtist).Name }
+ IncludeItemTypes = new[] { typeof(MusicArtist).Name },
+ DtoOptions = dtoOptions
}).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)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(Studio).Name }
+ IncludeItemTypes = new[] { typeof(Studio).Name },
+ DtoOptions = dtoOptions
}).OfType<Studio>().FirstOrDefault();
@@ -214,14 +216,15 @@ namespace MediaBrowser.Api
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)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(Genre).Name }
+ IncludeItemTypes = new[] { typeof(Genre).Name },
+ DtoOptions = dtoOptions
}).OfType<Genre>().FirstOrDefault();
@@ -234,14 +237,15 @@ namespace MediaBrowser.Api
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)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(MusicGenre).Name }
+ IncludeItemTypes = new[] { typeof(MusicGenre).Name },
+ DtoOptions = dtoOptions
}).OfType<MusicGenre>().FirstOrDefault();
@@ -254,14 +258,15 @@ namespace MediaBrowser.Api
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)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(GameGenre).Name }
+ IncludeItemTypes = new[] { typeof(GameGenre).Name },
+ DtoOptions = dtoOptions
}).OfType<GameGenre>().FirstOrDefault();
@@ -274,14 +279,15 @@ namespace MediaBrowser.Api
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)
{
var result = libraryManager.GetItemList(new InternalItemsQuery
{
SlugName = name,
- IncludeItemTypes = new[] { typeof(Person).Name }
+ IncludeItemTypes = new[] { typeof(Person).Name },
+ DtoOptions = dtoOptions
}).OfType<Person>().FirstOrDefault();
@@ -329,37 +335,33 @@ namespace MediaBrowser.Api
/// <summary>
/// Gets the name of the item by.
/// </summary>
- /// <param name="name">The name.</param>
- /// <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)
+ protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager, DtoOptions dtoOptions)
{
BaseItem item;
if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0)
{
- item = GetPerson(name, libraryManager);
+ item = GetPerson(name, libraryManager, dtoOptions);
}
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)
{
- item = GetGenre(name, libraryManager);
+ item = GetGenre(name, libraryManager, dtoOptions);
}
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)
{
- item = GetGameGenre(name, libraryManager);
+ item = GetGameGenre(name, libraryManager, dtoOptions);
}
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)
{
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index cbbaa82b8..6c4cc2217 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
@@ -406,7 +407,7 @@ namespace MediaBrowser.Api.Images
{
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);
}
@@ -415,7 +416,7 @@ namespace MediaBrowser.Api.Images
{
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);
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 3494754d0..a90c8d9e7 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -22,6 +22,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.LiveTv
{
@@ -698,8 +699,9 @@ namespace MediaBrowser.Api.LiveTv
private readonly IFileSystem _fileSystem;
private readonly IAuthorizationContext _authContext;
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;
_userManager = userManager;
@@ -710,6 +712,7 @@ namespace MediaBrowser.Api.LiveTv
_fileSystem = fileSystem;
_authContext = authContext;
_sessionContext = sessionContext;
+ _environment = environment;
}
public object Get(GetTunerHostTypes request)
@@ -731,7 +734,7 @@ namespace MediaBrowser.Api.LiveTv
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
};
@@ -750,7 +753,7 @@ namespace MediaBrowser.Api.LiveTv
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
};
diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index 797edd940..3cb29de07 100644
--- a/MediaBrowser.Api/Music/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -171,7 +171,7 @@ namespace MediaBrowser.Api.Music
public Task<object> Get(GetInstantMixFromArtist request)
{
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);
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index f0386d5ba..c0257b007 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive
{
@@ -35,6 +36,10 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated]
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>
/// Gets the specified request.
/// </summary>
@@ -61,9 +66,5 @@ namespace MediaBrowser.Api.Playback.Progressive
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)
- {
- }
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 646a91c27..db5c78a2f 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive
{
@@ -25,10 +26,12 @@ namespace MediaBrowser.Api.Playback.Progressive
public abstract class BaseProgressiveStreamingService : BaseStreamingService
{
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;
+ EnvironmentInfo = environmentInfo;
}
/// <summary>
@@ -130,7 +133,7 @@ namespace MediaBrowser.Api.Playback.Progressive
// TODO: Don't hardcode this
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
};
@@ -174,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Progressive
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
};
@@ -398,7 +401,7 @@ namespace MediaBrowser.Api.Playback.Progressive
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
{
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
index a33fbcbcf..d4d468913 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive
{
@@ -22,16 +23,16 @@ namespace MediaBrowser.Api.Playback.Progressive
private readonly CancellationToken _cancellationToken;
private readonly Dictionary<string, string> _outputHeaders;
- // 256k
- private const int BufferSize = 81920;
+ const int StreamCopyToBufferSize = 81920;
private long _bytesWritten = 0;
public long StartPosition { get; set; }
public bool AllowEndOfFile = true;
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;
_path = path;
@@ -39,15 +40,17 @@ namespace MediaBrowser.Api.Playback.Progressive
_job = job;
_logger = logger;
_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;
_outputHeaders = outputHeaders;
_job = job;
_logger = logger;
_cancellationToken = cancellationToken;
+ _environment = environment;
}
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)
{
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
+
try
{
if (_directStreamProvider != null)
{
- await _directStreamProvider.CopyToAsync(outputStream, _cancellationToken).ConfigureAwait(false);
+ await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
return;
}
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)
{
inputStream.Position = StartPosition;
}
- while (eofCount < 15 || !AllowEndOfFile)
+ while (eofCount < 20 || !AllowEndOfFile)
{
- var bytesRead = await CopyToAsyncInternal(inputStream, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false);
+ 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);
@@ -95,7 +120,7 @@ namespace MediaBrowser.Api.Playback.Progressive
{
eofCount++;
}
- await Task.Delay(100, _cancellationToken).ConfigureAwait(false);
+ await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
else
{
@@ -113,22 +138,54 @@ 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)
{
- byte[] buffer = new byte[bufferSize];
+ var array = new byte[StreamCopyToBufferSize];
int bytesRead;
int totalBytesRead = 0;
- while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
+ while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{
- await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
+ var bytesToWrite = bytesRead;
+
+ if (bytesToWrite > 0)
+ {
+ await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
- _bytesWritten += bytesRead;
- totalBytesRead += bytesRead;
+ _bytesWritten += bytesRead;
+ totalBytesRead += bytesRead;
- if (_job != null)
+ if (_job != null)
+ {
+ _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
+ }
+ }
+ }
+
+ 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)
{
- _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
+ 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);
+ }
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index c36a27690..5e21f6a84 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Model.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback.Progressive
{
@@ -66,7 +67,7 @@ namespace MediaBrowser.Api.Playback.Progressive
//[Authenticated]
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)
{
}
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
index ae64623df..c28014f9b 100644
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Api.Playback
{
@@ -63,7 +64,7 @@ namespace MediaBrowser.Api.Playback
//[Authenticated]
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;
UserManager = userManager;
@@ -80,6 +81,7 @@ namespace MediaBrowser.Api.Playback
AuthorizationContext = authorizationContext;
ImageProcessor = imageProcessor;
NetworkManager = networkManager;
+ EnvironmentInfo = environmentInfo;
}
protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
@@ -97,6 +99,7 @@ namespace MediaBrowser.Api.Playback
protected IAuthorizationContext AuthorizationContext { get; private set; }
protected IImageProcessor ImageProcessor { get; private set; }
protected INetworkManager NetworkManager { get; private set; }
+ protected IEnvironmentInfo EnvironmentInfo { get; private set; }
public Task<object> Get(GetUniversalAudioStream request)
{
@@ -263,7 +266,8 @@ namespace MediaBrowser.Api.Playback
ZipClient,
JsonSerializer,
AuthorizationContext,
- ImageProcessor)
+ ImageProcessor,
+ EnvironmentInfo)
{
Request = Request
};
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index 5bbd96c7c..7c1519e9f 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -68,10 +68,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetArtist request)
{
- var item = GetArtist(request.Name, LibraryManager);
-
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
+ var item = GetArtist(request.Name, LibraryManager, dtoOptions);
+
if (!string.IsNullOrWhiteSpace(request.UserId))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index daef97915..d79fafd32 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -267,7 +267,8 @@ namespace MediaBrowser.Api.UserLibrary
{
ExcludeItemTypes = excludeItemTypes,
IncludeItemTypes = includeItemTypes,
- MediaTypes = mediaTypes
+ MediaTypes = mediaTypes,
+ DtoOptions = dtoOptions
};
Func<BaseItem, bool> filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes);
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index 2eef1ab2f..56730c1b2 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -56,10 +56,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetGameGenre request)
{
- var item = GetGameGenre(request.Name, LibraryManager);
-
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
-
+
+ var item = GetGameGenre(request.Name, LibraryManager, dtoOptions);
+
if (!string.IsNullOrWhiteSpace(request.UserId))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 664efac14..fc387e5e3 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -66,10 +66,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
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))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index da5c5c763..b7bb758c3 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -358,7 +358,7 @@ namespace MediaBrowser.Api.UserLibrary
{
try
{
- return _libraryManager.GetArtist(i);
+ return _libraryManager.GetArtist(i, new DtoOptions(false));
}
catch
{
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 305c136df..d1d4aa634 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -57,10 +57,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetMusicGenre request)
{
- var item = GetMusicGenre(request.Name, LibraryManager);
-
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
+ var item = GetMusicGenre(request.Name, LibraryManager, dtoOptions);
+
if (!string.IsNullOrWhiteSpace(request.UserId))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index dbce22578..21f416025 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -64,10 +64,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetPerson request)
{
- var item = GetPerson(request.Name, LibraryManager);
-
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
+ var item = GetPerson(request.Name, LibraryManager, dtoOptions);
+
if (!string.IsNullOrWhiteSpace(request.UserId))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index f4debcf48..7ac1264e8 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -66,10 +66,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{BaseItemDto}.</returns>
private BaseItemDto GetItem(GetStudio request)
{
- var item = GetStudio(request.Name, LibraryManager);
-
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
-
+
+ var item = GetStudio(request.Name, LibraryManager, dtoOptions);
+
if (!string.IsNullOrWhiteSpace(request.UserId))
{
var user = UserManager.GetUserById(request.UserId);
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index f40ab3cde..e9eca19cf 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -8,6 +8,7 @@ using System.Linq;
using MediaBrowser.Model.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
@@ -42,20 +43,22 @@ namespace MediaBrowser.Controller.Entities.Audio
[IgnoreDataMember]
public MusicArtist MusicArtist
{
- get
- {
- var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
+ get { return GetMusicArtist(new DtoOptions(true)); }
+ }
- if (artist == null)
+ public MusicArtist GetMusicArtist(DtoOptions options)
+ {
+ var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
+
+ if (artist == null)
+ {
+ var name = AlbumArtist;
+ if (!string.IsNullOrWhiteSpace(name))
{
- var name = AlbumArtist;
- if (!string.IsNullOrWhiteSpace(name))
- {
- artist = LibraryManager.GetArtist(name);
- }
+ artist = LibraryManager.GetArtist(name, options);
}
- return artist;
}
+ return artist;
}
[IgnoreDataMember]
@@ -171,7 +174,7 @@ namespace MediaBrowser.Controller.Entities.Audio
id.AlbumArtists = AlbumArtists;
- var artist = MusicArtist;
+ var artist = GetMusicArtist(new DtoOptions(false));
if (artist != null)
{
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index f029d36fd..d3220f6c1 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -160,42 +160,6 @@ namespace MediaBrowser.Controller.Entities
public DtoOptions DtoOptions { 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()
{
MinSimilarityScore = 20;
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 70a635872..7dcc207db 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
@@ -68,18 +69,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="name">The name.</param>
/// <returns>Task{Artist}.</returns>
MusicArtist GetArtist(string name);
- /// <summary>
- /// 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);
+ MusicArtist GetArtist(string name, DtoOptions options);
/// <summary>
/// Gets a Studio
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs
index 0908c3ecc..48468d1a0 100644
--- a/MediaBrowser.Controller/LiveTv/LiveStream.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs
@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.System;
namespace MediaBrowser.Controller.LiveTv
{
@@ -10,7 +13,8 @@ namespace MediaBrowser.Controller.LiveTv
{
public MediaSourceInfo OriginalMediaSource { get; set; }
public MediaSourceInfo OpenedMediaSource { get; set; }
- public int ConsumerCount {
+ public int ConsumerCount
+ {
get { return SharedStreamIds.Count; }
}
public ITunerHost TunerHost { get; set; }
@@ -18,11 +22,16 @@ namespace MediaBrowser.Controller.LiveTv
public bool EnableStreamSharing { get; set; }
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;
+ Environment = environment;
+ FileSystem = fileSystem;
OpenedMediaSource = mediaSource;
EnableStreamSharing = true;
}
@@ -41,5 +50,131 @@ namespace MediaBrowser.Controller.LiveTv
{
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;
+ }
}
}
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index db35090b9..9a7052089 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -235,6 +235,9 @@
ExternalEtag,
PresentationUniqueKey,
InheritedParentalRatingValue,
- ExternalSeriesId
+ ExternalSeriesId,
+ SeriesPresentationUniqueKey,
+ DateLastRefreshed,
+ DateLastSaved
}
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index c6cdeb354..cf3e221b3 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -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();
// Don't cache if not configured to do so
@@ -330,7 +328,13 @@ namespace MediaBrowser.WebDashboard.Api
var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5();
- return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(basePath, path, localizationCulture)).ConfigureAwait(false);
+ // 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.GetStaticFileResult(Request, GetPackageCreator(basePath).GetResourcePath(path));
}
private string GetLocalizationCulture()
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 72389044b..ee911f0e9 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -68,7 +68,7 @@ namespace MediaBrowser.WebDashboard.Api
/// Gets the dashboard resource path.
/// </summary>
/// <returns>System.String.</returns>
- private string GetDashboardResourcePath(string virtualPath)
+ public string GetResourcePath(string virtualPath)
{
var fullPath = Path.Combine(_basePath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar));
@@ -97,7 +97,7 @@ namespace MediaBrowser.WebDashboard.Api
return false;
}
- path = GetDashboardResourcePath(path);
+ path = GetResourcePath(path);
var parent = _fileSystem.GetDirectoryName(path);
return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) ||
@@ -140,7 +140,7 @@ namespace MediaBrowser.WebDashboard.Api
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>");
}
@@ -299,7 +299,7 @@ namespace MediaBrowser.WebDashboard.Api
/// </summary>
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);
}
}
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 140f3c286..5a7ec0dba 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.17.9")]
+[assembly: AssemblyVersion("3.2.17.10")]
diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs
index 149b24028..b2d0d4e9c 100644
--- a/SocketHttpListener.Portable/Net/ResponseStream.cs
+++ b/SocketHttpListener.Portable/Net/ResponseStream.cs
@@ -148,6 +148,7 @@ namespace SocketHttpListener.Net
}
const int MsCopyBufferSize = 81920;
+ const int StreamCopyToBufferSize = 81920;
public override void Write(byte[] buffer, int offset, int count)
{
if (disposed)
@@ -340,11 +341,11 @@ namespace SocketHttpListener.Net
{
if (allowAsync)
{
- await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
+ await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
}
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)
{
- var array = new byte[81920];
+ var array = new byte[StreamCopyToBufferSize];
int bytesRead;
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{
- if (bytesRead == 0)
- {
- break;
- }
-
var bytesToWrite = Math.Min(bytesRead, copyLength);
if (bytesToWrite > 0)
@@ -380,16 +376,11 @@ namespace SocketHttpListener.Net
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;
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
- if (bytesRead == 0)
- {
- break;
- }
-
var bytesToWrite = Math.Min(bytesRead, copyLength);
if (bytesToWrite > 0)