mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-16 10:29:01 -07:00
commit
de1b647d97
@ -1415,66 +1415,69 @@ namespace Emby.Server.Implementations.Data
|
||||
|
||||
var index = 5;
|
||||
|
||||
var hasProgramAttributes = item as IHasProgramAttributes;
|
||||
if (hasProgramAttributes != null)
|
||||
if (HasProgramAttributes(query))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
var hasProgramAttributes = item as IHasProgramAttributes;
|
||||
if (hasProgramAttributes != null)
|
||||
{
|
||||
hasProgramAttributes.IsMovie = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsMovie = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsSports = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsSports = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsKids = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsKids = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsSeries = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsSeries = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsLive = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsLive = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsNews = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsNews = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsPremiere = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.EpisodeTitle = reader.GetString(index);
|
||||
}
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.EpisodeTitle = reader.GetString(index);
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += 9;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += 9;
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
@ -1483,7 +1486,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.CustomRating))
|
||||
if (HasField(query, ItemFields.CustomRating))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1498,7 +1501,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.Settings))
|
||||
if (HasField(query, ItemFields.Settings))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1525,7 +1528,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.ExternalEtag))
|
||||
if (HasField(query, ItemFields.ExternalEtag))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1534,11 +1537,14 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
if (HasField(query, ItemFields.DateLastRefreshed))
|
||||
{
|
||||
item.DateLastRefreshed = reader[index].ReadDateTime();
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
item.DateLastRefreshed = reader[index].ReadDateTime();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1558,7 +1564,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.Overview))
|
||||
if (HasField(query, ItemFields.Overview))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1585,7 +1591,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.HomePageUrl))
|
||||
if (HasField(query, ItemFields.HomePageUrl))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1594,7 +1600,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.DisplayMediaType))
|
||||
if (HasField(query, ItemFields.DisplayMediaType))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1603,7 +1609,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.SortName))
|
||||
if (HasField(query, ItemFields.SortName))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1618,7 +1624,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.VoteCount))
|
||||
if (HasField(query, ItemFields.VoteCount))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1627,7 +1633,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.DateCreated))
|
||||
if (HasField(query, ItemFields.DateCreated))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1645,7 +1651,7 @@ namespace Emby.Server.Implementations.Data
|
||||
item.Id = reader.GetGuid(index);
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.Genres))
|
||||
if (HasField(query, ItemFields.Genres))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1680,13 +1686,16 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (!reader.IsDBNull(index))
|
||||
if (HasField(query, ItemFields.DateLastSaved))
|
||||
{
|
||||
item.DateLastSaved = reader[index].ReadDateTime();
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
item.DateLastSaved = reader[index].ReadDateTime();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.Settings))
|
||||
if (HasField(query, ItemFields.Settings))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1695,7 +1704,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.Studios))
|
||||
if (HasField(query, ItemFields.Studios))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1704,7 +1713,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.Tags))
|
||||
if (HasField(query, ItemFields.Tags))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1729,7 +1738,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.OriginalTitle))
|
||||
if (HasField(query, ItemFields.OriginalTitle))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1748,7 +1757,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.DateLastMediaAdded))
|
||||
if (HasField(query, ItemFields.DateLastMediaAdded))
|
||||
{
|
||||
var folder = item as Folder;
|
||||
if (folder != null && !reader.IsDBNull(index))
|
||||
@ -1814,7 +1823,7 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (query.HasField(ItemFields.PresentationUniqueKey))
|
||||
if (HasField(query, ItemFields.PresentationUniqueKey))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1823,7 +1832,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.InheritedParentalRatingValue))
|
||||
if (HasField(query, ItemFields.InheritedParentalRatingValue))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1832,7 +1841,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.Tags))
|
||||
if (HasField(query, ItemFields.Tags))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1841,7 +1850,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.ExternalSeriesId))
|
||||
if (HasField(query, ItemFields.ExternalSeriesId))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1850,7 +1859,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.Taglines))
|
||||
if (HasField(query, ItemFields.Taglines))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1859,7 +1868,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.Keywords))
|
||||
if (HasField(query, ItemFields.Keywords))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1883,7 +1892,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.ProductionLocations))
|
||||
if (HasField(query, ItemFields.ProductionLocations))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1892,7 +1901,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.ThemeSongIds))
|
||||
if (HasField(query, ItemFields.ThemeSongIds))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1901,7 +1910,7 @@ namespace Emby.Server.Implementations.Data
|
||||
index++;
|
||||
}
|
||||
|
||||
if (query.HasField(ItemFields.ThemeVideoIds))
|
||||
if (HasField(query, ItemFields.ThemeVideoIds))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
@ -1942,14 +1951,17 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
index++;
|
||||
|
||||
if (hasSeries != null)
|
||||
if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
|
||||
{
|
||||
if (!reader.IsDBNull(index))
|
||||
if (hasSeries != null)
|
||||
{
|
||||
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
|
||||
return item;
|
||||
}
|
||||
@ -2259,13 +2271,73 @@ namespace Emby.Server.Implementations.Data
|
||||
return new[] { field.ToString() };
|
||||
}
|
||||
|
||||
private bool HasField(InternalItemsQuery query, ItemFields name)
|
||||
{
|
||||
var fields = query.DtoOptions.Fields;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case ItemFields.HomePageUrl:
|
||||
case ItemFields.Keywords:
|
||||
case ItemFields.DisplayMediaType:
|
||||
case ItemFields.VoteCount:
|
||||
case ItemFields.CustomRating:
|
||||
case ItemFields.ProductionLocations:
|
||||
case ItemFields.Settings:
|
||||
case ItemFields.OriginalTitle:
|
||||
case ItemFields.Taglines:
|
||||
case ItemFields.SortName:
|
||||
case ItemFields.Studios:
|
||||
case ItemFields.Tags:
|
||||
case ItemFields.ThemeSongIds:
|
||||
case ItemFields.ThemeVideoIds:
|
||||
case ItemFields.DateCreated:
|
||||
case ItemFields.Overview:
|
||||
case ItemFields.Genres:
|
||||
case ItemFields.DateLastMediaAdded:
|
||||
case ItemFields.ExternalEtag:
|
||||
case ItemFields.PresentationUniqueKey:
|
||||
case ItemFields.InheritedParentalRatingValue:
|
||||
case ItemFields.ExternalSeriesId:
|
||||
case ItemFields.SeriesPresentationUniqueKey:
|
||||
case ItemFields.DateLastRefreshed:
|
||||
case ItemFields.DateLastSaved:
|
||||
return fields.Contains(name);
|
||||
case ItemFields.ServiceName:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasProgramAttributes(InternalItemsQuery query)
|
||||
{
|
||||
if (query.IncludeItemTypes.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var types = new string[]
|
||||
{
|
||||
"Program",
|
||||
"Recording",
|
||||
"TvChannel",
|
||||
"LiveTvAudioRecording",
|
||||
"LiveTvVideoRecording",
|
||||
"LiveTvProgram",
|
||||
"LiveTvTvChannel"
|
||||
};
|
||||
|
||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
|
||||
{
|
||||
var list = startColumns.ToList();
|
||||
|
||||
foreach (var field in allFields)
|
||||
{
|
||||
if (!query.HasField(field))
|
||||
if (!HasField(query, field))
|
||||
{
|
||||
foreach (var fieldToRemove in GetColumnNamesFromField(field).ToList())
|
||||
{
|
||||
@ -2274,6 +2346,19 @@ namespace Emby.Server.Implementations.Data
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasProgramAttributes(query))
|
||||
{
|
||||
list.Remove("IsKids");
|
||||
list.Remove("IsMovie");
|
||||
list.Remove("IsSports");
|
||||
list.Remove("IsSeries");
|
||||
list.Remove("IsLive");
|
||||
list.Remove("IsNews");
|
||||
list.Remove("IsPremiere");
|
||||
list.Remove("EpisodeTitle");
|
||||
list.Remove("IsRepeat");
|
||||
}
|
||||
|
||||
if (!query.DtoOptions.EnableImages)
|
||||
{
|
||||
list.Remove("Images");
|
||||
@ -2400,7 +2485,7 @@ namespace Emby.Server.Implementations.Data
|
||||
query.Limit = query.Limit.Value + 4;
|
||||
}
|
||||
|
||||
var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new [] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
|
||||
var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" })) + GetFromText();
|
||||
commandText += GetJoinUserDataText(query);
|
||||
|
||||
var whereClauses = GetWhereClauses(query, null);
|
||||
@ -3671,6 +3756,7 @@ namespace Emby.Server.Implementations.Data
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.SlugName))
|
||||
{
|
||||
Logger.Info("Searching by SlugName for {0}", query.SlugName);
|
||||
whereClauses.Add("CleanName=@SlugName");
|
||||
if (statement != null)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
_bytesWritten += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (_job != null)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_bytesWritten += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (_job != null)
|
||||
{
|
||||
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -358,7 +358,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i);
|
||||
return _libraryManager.GetArtist(i, new DtoOptions(false));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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<MusicArtist>.</returns>
|
||||
IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items);
|
||||
/// <summary>
|
||||
/// Gets the artists.
|
||||
/// </summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <returns>IEnumerable<MusicArtist>.</returns>
|
||||
IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items);
|
||||
MusicArtist GetArtist(string name, DtoOptions options);
|
||||
/// <summary>
|
||||
/// Gets a Studio
|
||||
/// </summary>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +235,9 @@
|
||||
ExternalEtag,
|
||||
PresentationUniqueKey,
|
||||
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();
|
||||
|
||||
// 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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
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 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)
|
||||
|
Loading…
Reference in New Issue
Block a user