aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2017-05-31 15:40:34 -0400
committerGitHub <noreply@github.com>2017-05-31 15:40:34 -0400
commit91176d9ccc1dde8155c10411c70e62a9f4b059d5 (patch)
tree21365f5a8dd09534a53d9f88d2a7a3116f3f3f98 /Emby.Server.Implementations
parentc37c9a75073b1b9caa3af2c3bc62abd837bd630e (diff)
parent4e10daf646e0788409f2bc52ef70effa2616e3f3 (diff)
Merge pull request #2677 from MediaBrowser/beta
Beta
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs16
-rw-r--r--Emby.Server.Implementations/Collections/CollectionImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs5
-rw-r--r--Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs652
-rw-r--r--Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs2
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs1
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs149
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj26
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs2
-rw-r--r--Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs8
-rw-r--r--Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs2
-rw-r--r--Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs8
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs18
-rw-r--r--Emby.Server.Implementations/HttpServer/IHttpListener.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs18
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs5
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs10
-rw-r--r--Emby.Server.Implementations/HttpServer/StreamWriter.cs2
-rw-r--r--Emby.Server.Implementations/IO/AsyncStreamCopier.cs459
-rw-r--r--Emby.Server.Implementations/IO/FileRefresher.cs16
-rw-r--r--Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs2
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs59
-rw-r--r--Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs123
-rw-r--r--Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs7
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs48
-rw-r--r--Emby.Server.Implementations/Library/ResolverHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs13
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs8
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs10
-rw-r--r--Emby.Server.Implementations/Library/Validators/PeopleValidator.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs33
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs47
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs32
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs9
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs30
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs66
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs23
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs88
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs53
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs193
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs9
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs59
-rw-r--r--Emby.Server.Implementations/MediaEncoder/EncodingManager.cs2
-rw-r--r--Emby.Server.Implementations/Migrations/GuideMigration.cs4
-rw-r--r--Emby.Server.Implementations/Migrations/LibraryScanMigration.cs4
-rw-r--r--Emby.Server.Implementations/Migrations/UpdateLevelMigration.cs130
-rw-r--r--Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs21
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs28
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs6
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs2
-rw-r--r--Emby.Server.Implementations/ServerManager/ServerManager.cs2
-rw-r--r--Emby.Server.Implementations/ServerManager/WebSocketConnection.cs1
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs37
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs6
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs8
-rw-r--r--Emby.Server.Implementations/Session/HttpSessionController.cs26
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs36
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs23
-rw-r--r--Emby.Server.Implementations/TV/SeriesPostScanTask.cs7
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs34
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs64
-rw-r--r--Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs28
-rw-r--r--Emby.Server.Implementations/UserViews/DynamicImageProvider.cs22
79 files changed, 1819 insertions, 1037 deletions
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 0cdd934b7..809771b04 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -23,7 +23,7 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.Channels
if (query.IsFavorite.HasValue)
{
var val = query.IsFavorite.Value;
- channels = channels.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val)
+ channels = channels.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val)
.ToList();
}
@@ -263,7 +263,7 @@ namespace Emby.Server.Implementations.Channels
}
catch
{
-
+
}
return;
}
@@ -273,7 +273,7 @@ namespace Emby.Server.Implementations.Channels
_jsonSerializer.SerializeToFile(mediaSources, path);
}
- public async Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken)
+ public IEnumerable<MediaSourceInfo> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken)
{
IEnumerable<ChannelMediaInfo> results = GetSavedMediaSources(item);
@@ -460,12 +460,12 @@ namespace Emby.Server.Implementations.Channels
public IEnumerable<ChannelFeatures> GetAllChannelFeatures()
{
- return _libraryManager.GetItemList(new InternalItemsQuery
+ return _libraryManager.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Channel).Name },
SortBy = new[] { ItemSortBy.SortName }
- }).Select(i => GetChannelFeatures(i.Id.ToString("N")));
+ }).Select(i => GetChannelFeatures(i.ToString("N")));
}
public ChannelFeatures GetChannelFeatures(string id)
@@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Channels
}
}
- return await GetReturnItems(internalItems, providerTotalRecordCount, user, query).ConfigureAwait(false);
+ return GetReturnItems(internalItems, providerTotalRecordCount, user, query);
}
public async Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken)
@@ -1154,7 +1154,7 @@ namespace Emby.Server.Implementations.Channels
filename + ".json");
}
- private async Task<QueryResult<BaseItem>> GetReturnItems(IEnumerable<BaseItem> items,
+ private QueryResult<BaseItem> GetReturnItems(IEnumerable<BaseItem> items,
int? totalCountFromProvider,
User user,
ChannelItemQuery query)
diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
index b82d4e44e..463d276e5 100644
--- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Collections
return base.Supports(item);
}
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var playlist = (BoxSet)item;
@@ -73,10 +73,10 @@ namespace Emby.Server.Implementations.Collections
.DistinctBy(i => i.Id)
.ToList();
- return Task.FromResult(GetFinalItems(items, 2));
+ return GetFinalItems(items, 2);
}
- protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
}
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 9c26655fc..4e5d344a3 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -170,6 +170,11 @@ namespace Emby.Server.Implementations.Collections
{
var item = _libraryManager.GetItemById(itemId);
+ if (string.IsNullOrWhiteSpace(item.Path))
+ {
+ continue;
+ }
+
if (item == null)
{
throw new ArgumentException("No item exists with the supplied Id");
diff --git a/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs
index 4ff33e645..c7bcdfe25 100644
--- a/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs
+++ b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using System.IO;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 451ec2dfe..3c4b50eda 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -207,8 +207,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "DateCreated", "DATETIME", existingColumnNames);
AddColumn(db, "TypedBaseItems", "DateModified", "DATETIME", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "ForcedSortName", "Text", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "IsSeries", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsLive", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsNews", "BIT", existingColumnNames);
@@ -241,7 +239,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "InheritedTags", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "CleanName", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "PresentationUniqueKey", "Text", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "SlugName", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "OriginalTitle", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "PrimaryVersionId", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "DateLastMediaAdded", "DATETIME", existingColumnNames);
@@ -427,7 +424,7 @@ namespace Emby.Server.Implementations.Data
"OfficialRating",
"HomePageUrl",
"DisplayMediaType",
- "ForcedSortName",
+ "SortName",
"RunTimeTicks",
"VoteCount",
"DateCreated",
@@ -550,7 +547,6 @@ namespace Emby.Server.Implementations.Data
"DisplayMediaType",
"DateCreated",
"DateModified",
- "ForcedSortName",
"PreferredMetadataLanguage",
"PreferredMetadataCountryCode",
"IsHD",
@@ -573,7 +569,6 @@ namespace Emby.Server.Implementations.Data
"InheritedTags",
"CleanName",
"PresentationUniqueKey",
- "SlugName",
"OriginalTitle",
"PrimaryVersionId",
"DateLastMediaAdded",
@@ -828,8 +823,6 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@DateCreated", item.DateCreated);
saveItemStatement.TryBind("@DateModified", item.DateModified);
- saveItemStatement.TryBind("@ForcedSortName", item.ForcedSortName);
-
saveItemStatement.TryBind("@PreferredMetadataLanguage", item.PreferredMetadataLanguage);
saveItemStatement.TryBind("@PreferredMetadataCountryCode", item.PreferredMetadataCountryCode);
saveItemStatement.TryBind("@IsHD", item.IsHD);
@@ -950,7 +943,6 @@ namespace Emby.Server.Implementations.Data
}
saveItemStatement.TryBind("@PresentationUniqueKey", item.PresentationUniqueKey);
- saveItemStatement.TryBind("@SlugName", item.SlugName);
saveItemStatement.TryBind("@OriginalTitle", item.OriginalTitle);
var video = item as Video;
@@ -1240,7 +1232,7 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
- return GetItem(row);
+ return GetItem(row, new InternalItemsQuery());
}
}
@@ -1249,19 +1241,10 @@ namespace Emby.Server.Implementations.Data
}
}
- private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader)
- {
- return GetItem(reader, new InternalItemsQuery());
- }
-
private bool TypeRequiresDeserialization(Type type)
{
if (_config.Configuration.SkipDeserializationForBasicTypes)
{
- if (type == typeof(Person))
- {
- return false;
- }
if (type == typeof(Channel))
{
return false;
@@ -1280,6 +1263,10 @@ namespace Emby.Server.Implementations.Data
}
}
+ if (type == typeof(Person))
+ {
+ return false;
+ }
if (type == typeof(MusicGenre))
{
return false;
@@ -1361,6 +1348,11 @@ namespace Emby.Server.Implementations.Data
private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader, InternalItemsQuery query)
{
+ return GetItem(reader, query, HasProgramAttributes(query), HasEpisodeAttributes(query), HasStartDate(query), HasTrailerTypes(query), HasArtistFields(query), HasSeriesFields(query));
+ }
+
+ private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader, InternalItemsQuery query, bool enableProgramAttributes, bool hasEpisodeAttributes, bool queryHasStartDate, bool hasTrailerTypes, bool hasArtistFields, bool hasSeriesFields)
+ {
var typeString = reader.GetString(0);
var type = _typeMapper.GetType(typeString);
@@ -1407,87 +1399,96 @@ namespace Emby.Server.Implementations.Data
return null;
}
- if (!reader.IsDBNull(2))
+ var index = 2;
+
+ if (queryHasStartDate)
{
- var hasStartDate = item as IHasStartDate;
- if (hasStartDate != null)
+ if (!reader.IsDBNull(index))
{
- hasStartDate.StartDate = reader[2].ReadDateTime();
+ var hasStartDate = item as IHasStartDate;
+ if (hasStartDate != null)
+ {
+ hasStartDate.StartDate = reader[index].ReadDateTime();
+ }
}
+ index++;
}
- if (!reader.IsDBNull(3))
+ if (!reader.IsDBNull(index))
{
- item.EndDate = reader[3].ReadDateTime();
+ item.EndDate = reader[index].ReadDateTime();
}
+ index++;
- if (!reader.IsDBNull(4))
+ if (!reader.IsDBNull(index))
{
- item.ChannelId = reader.GetString(4);
+ item.ChannelId = reader.GetString(index);
}
+ index++;
- var index = 5;
-
- var hasProgramAttributes = item as IHasProgramAttributes;
- if (hasProgramAttributes != null)
+ if (enableProgramAttributes)
{
- 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))
@@ -1496,7 +1497,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.CustomRating))
+ if (HasField(query, ItemFields.CustomRating))
{
if (!reader.IsDBNull(index))
{
@@ -1511,7 +1512,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.Settings))
+ if (HasField(query, ItemFields.Settings))
{
if (!reader.IsDBNull(index))
{
@@ -1538,17 +1539,23 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.ExternalEtag))
{
- item.ExternalEtag = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ item.ExternalEtag = reader.GetString(index);
+ }
+ index++;
}
- 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))
{
@@ -1568,7 +1575,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.Overview))
+ if (HasField(query, ItemFields.Overview))
{
if (!reader.IsDBNull(index))
{
@@ -1595,7 +1602,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.HomePageUrl))
+ if (HasField(query, ItemFields.HomePageUrl))
{
if (!reader.IsDBNull(index))
{
@@ -1604,7 +1611,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.DisplayMediaType))
+ if (HasField(query, ItemFields.DisplayMediaType))
{
if (!reader.IsDBNull(index))
{
@@ -1613,11 +1620,11 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.SortName))
+ if (HasField(query, ItemFields.SortName))
{
if (!reader.IsDBNull(index))
{
- item.ForcedSortName = reader.GetString(index);
+ item.SortName = reader.GetString(index);
}
index++;
}
@@ -1628,7 +1635,7 @@ namespace Emby.Server.Implementations.Data
}
index++;
- if (query.HasField(ItemFields.VoteCount))
+ if (HasField(query, ItemFields.VoteCount))
{
if (!reader.IsDBNull(index))
{
@@ -1637,7 +1644,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.DateCreated))
+ if (HasField(query, ItemFields.DateCreated))
{
if (!reader.IsDBNull(index))
{
@@ -1655,7 +1662,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))
{
@@ -1690,13 +1697,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))
{
@@ -1705,7 +1715,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Studios))
+ if (HasField(query, ItemFields.Studios))
{
if (!reader.IsDBNull(index))
{
@@ -1714,7 +1724,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Tags))
+ if (HasField(query, ItemFields.Tags))
{
if (!reader.IsDBNull(index))
{
@@ -1729,17 +1739,20 @@ namespace Emby.Server.Implementations.Data
}
index++;
- var trailer = item as Trailer;
- if (trailer != null)
+ if (hasTrailerTypes)
{
- if (!reader.IsDBNull(index))
+ var trailer = item as Trailer;
+ if (trailer != null)
{
- trailer.TrailerTypes = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true)).ToList();
+ if (!reader.IsDBNull(index))
+ {
+ trailer.TrailerTypes = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true)).ToList();
+ }
}
+ index++;
}
- index++;
- if (query.HasField(ItemFields.OriginalTitle))
+ if (HasField(query, ItemFields.OriginalTitle))
{
if (!reader.IsDBNull(index))
{
@@ -1758,7 +1771,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))
@@ -1787,68 +1800,89 @@ namespace Emby.Server.Implementations.Data
index++;
var hasSeries = item as IHasSeries;
- if (hasSeries != null)
+ if (hasSeriesFields)
{
- if (!reader.IsDBNull(index))
+ if (hasSeries != null)
{
- hasSeries.SeriesName = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ hasSeries.SeriesName = reader.GetString(index);
+ }
}
+ index++;
}
- index++;
- var episode = item as Episode;
- if (episode != null)
+ if (hasEpisodeAttributes)
{
- if (!reader.IsDBNull(index))
+ var episode = item as Episode;
+ if (episode != null)
{
- episode.SeasonName = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ episode.SeasonName = reader.GetString(index);
+ }
+ index++;
+ if (!reader.IsDBNull(index))
+ {
+ episode.SeasonId = reader.GetGuid(index);
+ }
}
- index++;
- if (!reader.IsDBNull(index))
+ else
{
- episode.SeasonId = reader.GetGuid(index);
+ index++;
}
+ index++;
}
- else
+
+ if (hasSeriesFields)
{
+ if (hasSeries != null)
+ {
+ if (!reader.IsDBNull(index))
+ {
+ hasSeries.SeriesId = reader.GetGuid(index);
+ }
+ }
index++;
}
- index++;
- if (hasSeries != null)
+ if (HasField(query, ItemFields.PresentationUniqueKey))
{
if (!reader.IsDBNull(index))
{
- hasSeries.SeriesId = reader.GetGuid(index);
+ item.PresentationUniqueKey = reader.GetString(index);
}
+ index++;
}
- index++;
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.InheritedParentalRatingValue))
{
- item.PresentationUniqueKey = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ item.InheritedParentalRatingValue = reader.GetInt32(index);
+ }
+ index++;
}
- index++;
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.Tags))
{
- item.InheritedParentalRatingValue = reader.GetInt32(index);
- }
- index++;
-
- if (!reader.IsDBNull(index))
- {
- item.InheritedTags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ if (!reader.IsDBNull(index))
+ {
+ item.InheritedTags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
+ index++;
}
- index++;
- if (!reader.IsDBNull(index))
+ if (HasField(query, ItemFields.ExternalSeriesId))
{
- item.ExternalSeriesId = reader.GetString(index);
+ if (!reader.IsDBNull(index))
+ {
+ item.ExternalSeriesId = reader.GetString(index);
+ }
+ index++;
}
- index++;
- if (query.HasField(ItemFields.Taglines))
+ if (HasField(query, ItemFields.Taglines))
{
if (!reader.IsDBNull(index))
{
@@ -1857,7 +1891,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.Keywords))
+ if (HasField(query, ItemFields.Keywords))
{
if (!reader.IsDBNull(index))
{
@@ -1881,7 +1915,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ProductionLocations))
+ if (HasField(query, ItemFields.ProductionLocations))
{
if (!reader.IsDBNull(index))
{
@@ -1890,7 +1924,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ThemeSongIds))
+ if (HasField(query, ItemFields.ThemeSongIds))
{
if (!reader.IsDBNull(index))
{
@@ -1899,7 +1933,7 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (query.HasField(ItemFields.ThemeVideoIds))
+ if (HasField(query, ItemFields.ThemeVideoIds))
{
if (!reader.IsDBNull(index))
{
@@ -1920,19 +1954,22 @@ namespace Emby.Server.Implementations.Data
}
index++;
- var hasArtists = item as IHasArtist;
- if (hasArtists != null && !reader.IsDBNull(index))
+ if (hasArtistFields)
{
- hasArtists.Artists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- }
- index++;
+ var hasArtists = item as IHasArtist;
+ if (hasArtists != null && !reader.IsDBNull(index))
+ {
+ hasArtists.Artists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
+ index++;
- var hasAlbumArtists = item as IHasAlbumArtist;
- if (hasAlbumArtists != null && !reader.IsDBNull(index))
- {
- hasAlbumArtists.AlbumArtists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ var hasAlbumArtists = item as IHasAlbumArtist;
+ if (hasAlbumArtists != null && !reader.IsDBNull(index))
+ {
+ hasAlbumArtists.AlbumArtists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ }
+ index++;
}
- index++;
if (!reader.IsDBNull(index))
{
@@ -1940,14 +1977,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;
}
@@ -2243,23 +2283,225 @@ namespace Emby.Server.Implementations.Data
}
if (field == ItemFields.SortName)
{
- return new[] { "ForcedSortName" };
+ return new[] { "SortName" };
}
if (field == ItemFields.Taglines)
{
return new[] { "Tagline" };
}
+ if (field == ItemFields.Tags)
+ {
+ return new[] { "Tags", "InheritedTags" };
+ }
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)
+ {
+ var excludeParentTypes = new string[]
+ {
+ "Series",
+ "Season",
+ "MusicAlbum",
+ "MusicArtist",
+ "PhotoAlbum"
+ };
+
+ if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ 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 bool HasStartDate(InternalItemsQuery query)
+ {
+ var excludeParentTypes = new string[]
+ {
+ "Series",
+ "Season",
+ "MusicAlbum",
+ "MusicArtist",
+ "PhotoAlbum"
+ };
+
+ if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Program",
+ "Recording",
+ "LiveTvAudioRecording",
+ "LiveTvVideoRecording",
+ "LiveTvProgram"
+ };
+
+ return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
+ }
+
+ private bool HasEpisodeAttributes(InternalItemsQuery query)
+ {
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Episode"
+ };
+
+ return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
+ }
+
+ private bool HasTrailerTypes(InternalItemsQuery query)
+ {
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Trailer"
+ };
+
+ return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
+ }
+
+ private bool HasArtistFields(InternalItemsQuery query)
+ {
+ var excludeParentTypes = new string[]
+ {
+ "Series",
+ "Season",
+ "PhotoAlbum"
+ };
+
+ if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Audio",
+ "MusicAlbum",
+ "MusicVideo",
+ "AudioBook",
+ "AudioPodcast",
+ "LiveTvAudioRecording",
+ "Recording"
+ };
+
+ return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
+ }
+
+ private bool HasSeriesFields(InternalItemsQuery query)
+ {
+ var excludeParentTypes = new string[]
+ {
+ "PhotoAlbum"
+ };
+
+ if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (query.IncludeItemTypes.Length == 0)
+ {
+ return true;
+ }
+
+ var types = new string[]
+ {
+ "Book",
+ "AudioBook",
+ "Episode",
+ "Season"
+ };
+
+ 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())
{
@@ -2268,6 +2510,53 @@ 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 (!HasEpisodeAttributes(query))
+ {
+ list.Remove("SeasonName");
+ list.Remove("SeasonId");
+ }
+
+ if (!HasStartDate(query))
+ {
+ list.Remove("StartDate");
+ }
+
+ if (!HasTrailerTypes(query))
+ {
+ list.Remove("TrailerTypes");
+ }
+
+ if (!HasArtistFields(query))
+ {
+ list.Remove("AlbumArtists");
+ list.Remove("Artists");
+ }
+
+ if (!HasSeriesFields(query))
+ {
+ list.Remove("SeriesId");
+ list.Remove("SeriesName");
+ }
+
+ if (!HasEpisodeAttributes(query))
+ {
+ list.Remove("SeasonName");
+ list.Remove("SeasonId");
+ }
+
if (!query.DtoOptions.EnableImages)
{
list.Remove("Images");
@@ -2394,7 +2683,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);
@@ -2499,9 +2788,16 @@ namespace Emby.Server.Implementations.Data
// Running this again will bind the params
GetWhereClauses(query, statement);
+ var hasEpisodeAttributes = HasEpisodeAttributes(query);
+ var hasProgramAttributes = HasProgramAttributes(query);
+ var hasStartDate = HasStartDate(query);
+ var hasTrailerTypes = HasTrailerTypes(query);
+ var hasArtistFields = HasArtistFields(query);
+ var hasSeriesFields = HasSeriesFields(query);
+
foreach (var row in statement.ExecuteQuery())
{
- var item = GetItem(row, query);
+ var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
if (item != null)
{
list.Add(item);
@@ -2701,9 +2997,16 @@ namespace Emby.Server.Implementations.Data
// Running this again will bind the params
GetWhereClauses(query, statement);
+ var hasEpisodeAttributes = HasEpisodeAttributes(query);
+ var hasProgramAttributes = HasProgramAttributes(query);
+ var hasStartDate = HasStartDate(query);
+ var hasTrailerTypes = HasTrailerTypes(query);
+ var hasArtistFields = HasArtistFields(query);
+ var hasSeriesFields = HasSeriesFields(query);
+
foreach (var row in statement.ExecuteQuery())
{
- var item = GetItem(row, query);
+ var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
if (item != null)
{
list.Add(item);
@@ -3471,6 +3774,15 @@ namespace Emby.Server.Implementations.Data
}
}
+ if (query.MinDateLastSavedForUser.HasValue)
+ {
+ whereClauses.Add("DateLastSaved>=@MinDateLastSaved");
+ if (statement != null)
+ {
+ statement.TryBind("@MinDateLastSaved", query.MinDateLastSavedForUser.Value);
+ }
+ }
+
//if (query.MinPlayers.HasValue)
//{
// whereClauses.Add("Players>=@MinPlayers");
@@ -3665,10 +3977,10 @@ namespace Emby.Server.Implementations.Data
if (!string.IsNullOrWhiteSpace(query.SlugName))
{
- whereClauses.Add("SlugName=@SlugName");
+ whereClauses.Add("CleanName=@SlugName");
if (statement != null)
{
- statement.TryBind("@SlugName", query.SlugName);
+ statement.TryBind("@SlugName", GetCleanValue(query.SlugName));
}
}
@@ -4919,7 +5231,9 @@ namespace Emby.Server.Implementations.Data
var columns = _retriveItemColumns.ToList();
columns.AddRange(itemCountColumns.Select(i => i.Item2).ToArray());
- var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, columns.ToArray())) + GetFromText();
+ columns = GetFinalColumnsToSelect(query, columns.ToArray()).ToList();
+
+ var commandText = "select " + string.Join(",", columns.ToArray()) + GetFromText();
commandText += GetJoinUserDataText(query);
var innerQuery = new InternalItemsQuery(query.User)
@@ -4962,7 +5276,6 @@ namespace Emby.Server.Implementations.Data
NameLessThan = query.NameLessThan,
NameStartsWith = query.NameStartsWith,
NameStartsWithOrGreater = query.NameStartsWithOrGreater,
- AlbumArtistStartsWithOrGreater = query.AlbumArtistStartsWithOrGreater,
Tags = query.Tags,
OfficialRatings = query.OfficialRatings,
GenreIds = query.GenreIds,
@@ -5043,9 +5356,16 @@ namespace Emby.Server.Implementations.Data
GetWhereClauses(innerQuery, statement);
GetWhereClauses(outerQuery, statement);
+ var hasEpisodeAttributes = HasEpisodeAttributes(query);
+ var hasProgramAttributes = HasProgramAttributes(query);
+ var hasStartDate = HasStartDate(query);
+ var hasTrailerTypes = HasTrailerTypes(query);
+ var hasArtistFields = HasArtistFields(query);
+ var hasSeriesFields = HasSeriesFields(query);
+
foreach (var row in statement.ExecuteQuery())
{
- var item = GetItem(row);
+ var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields);
if (item != null)
{
var countStartColumn = columns.Count - 1;
diff --git a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
index e2d5d0272..52979f085 100644
--- a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
+++ b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
@@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Providers;
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index b246ef196..027a55516 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -16,7 +16,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index d784bcb09..45fbd69dc 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -24,7 +24,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Extensions;
@@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Dto
foreach (var item in items)
{
- var dto = await GetBaseItemDtoInternal(item, options, user, owner).ConfigureAwait(false);
+ var dto = GetBaseItemDtoInternal(item, options, user, owner);
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
@@ -127,7 +127,11 @@ namespace Emby.Server.Implementations.Dto
{
var libraryItems = byName.GetTaggedItems(new InternalItemsQuery(user)
{
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(false)
+ {
+ EnableImages = false
+ }
});
SetItemByNameInfo(item, dto, libraryItems.ToList(), user);
@@ -156,7 +160,7 @@ namespace Emby.Server.Implementations.Dto
{
var syncDictionary = GetSyncedItemProgress(options);
- var dto = GetBaseItemDtoInternal(item, options, user, owner).Result;
+ var dto = GetBaseItemDtoInternal(item, options, user, owner);
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
{
@@ -177,7 +181,11 @@ namespace Emby.Server.Implementations.Dto
{
if (options.Fields.Contains(ItemFields.ItemCounts))
{
- SetItemByNameInfo(item, dto, GetTaggedItems(byName, user), user);
+ SetItemByNameInfo(item, dto, GetTaggedItems(byName, user, new DtoOptions(false)
+ {
+ EnableImages = false
+
+ }), user);
}
FillSyncInfo(dto, item, options, user, syncDictionary);
@@ -189,11 +197,12 @@ namespace Emby.Server.Implementations.Dto
return dto;
}
- private List<BaseItem> GetTaggedItems(IItemByName byName, User user)
+ private List<BaseItem> GetTaggedItems(IItemByName byName, User user, DtoOptions options)
{
var items = byName.GetTaggedItems(new InternalItemsQuery(user)
{
- Recursive = true
+ Recursive = true,
+ DtoOptions = options
}).ToList();
@@ -283,7 +292,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- private async Task<BaseItemDto> GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
+ private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
{
var fields = options.Fields;
@@ -332,7 +341,7 @@ namespace Emby.Server.Implementations.Dto
if (user != null)
{
- await AttachUserSpecificInfo(dto, item, user, options).ConfigureAwait(false);
+ AttachUserSpecificInfo(dto, item, user, options);
}
var hasMediaSources = item as IHasMediaSources;
@@ -393,7 +402,7 @@ namespace Emby.Server.Implementations.Dto
public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null)
{
- var dto = GetBaseItemDtoInternal(item, options, user).Result;
+ var dto = GetBaseItemDtoInternal(item, options, user);
if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts))
{
@@ -446,7 +455,7 @@ namespace Emby.Server.Implementations.Dto
/// <summary>
/// Attaches the user specific info.
/// </summary>
- private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions)
+ private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions)
{
var fields = dtoOptions.Fields;
@@ -456,7 +465,7 @@ namespace Emby.Server.Implementations.Dto
if (dtoOptions.EnableUserData)
{
- dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields).ConfigureAwait(false);
+ dto.UserData = _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields);
}
if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library)
@@ -488,7 +497,7 @@ namespace Emby.Server.Implementations.Dto
{
if (dtoOptions.EnableUserData)
{
- dto.UserData = await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false);
+ dto.UserData = _userDataRepository.GetUserDataDto(item, user);
}
}
@@ -595,16 +604,17 @@ namespace Emby.Server.Implementations.Dto
{
if (!string.IsNullOrEmpty(item.Album))
{
- var parentAlbum = _libraryManager.GetItemList(new InternalItemsQuery
+ var parentAlbumIds = _libraryManager.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(MusicAlbum).Name },
- Name = item.Album
+ Name = item.Album,
+ Limit = 1
- }).FirstOrDefault();
+ });
- if (parentAlbum != null)
+ if (parentAlbumIds.Count > 0)
{
- dto.AlbumId = GetDtoId(parentAlbum);
+ dto.AlbumId = parentAlbumIds[0].ToString("N");
}
}
@@ -751,45 +761,41 @@ namespace Emby.Server.Implementations.Dto
/// <returns>Task.</returns>
private void AttachStudios(BaseItemDto dto, BaseItem item)
{
- var studios = item.Studios.ToList();
-
- dto.Studios = new StudioDto[studios.Count];
-
- var dictionary = studios.Distinct(StringComparer.OrdinalIgnoreCase).Select(name =>
- {
- try
- {
- return _libraryManager.GetStudio(name);
- }
- catch (IOException ex)
+ dto.Studios = item.Studios
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => new NameIdPair
{
- _logger.ErrorException("Error getting studio {0}", ex, name);
- return null;
- }
- })
- .Where(i => i != null)
- .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
-
- for (var i = 0; i < studios.Count; i++)
- {
- var studio = studios[i];
+ Name = i,
+ Id = _libraryManager.GetStudioId(i).ToString("N")
+ })
+ .ToArray();
+ }
- var studioDto = new StudioDto
+ private void AttachGenreItems(BaseItemDto dto, BaseItem item)
+ {
+ dto.GenreItems = item.Genres
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Select(i => new NameIdPair
{
- Name = studio
- };
-
- Studio entity;
+ Name = i,
+ Id = GetStudioId(i, item)
+ })
+ .ToArray();
+ }
- if (dictionary.TryGetValue(studio, out entity))
- {
- studioDto.Id = entity.Id.ToString("N");
- studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
- }
+ private string GetStudioId(string name, BaseItem owner)
+ {
+ if (owner is IHasMusicGenres)
+ {
+ return _libraryManager.GetGameGenreId(name).ToString("N");
+ }
- dto.Studios[i] = studioDto;
+ if (owner is Game || owner is GameSystem)
+ {
+ return _libraryManager.GetGameGenreId(name).ToString("N");
}
+
+ return _libraryManager.GetGenreId(name).ToString("N");
}
/// <summary>
@@ -901,6 +907,7 @@ namespace Emby.Server.Implementations.Dto
if (fields.Contains(ItemFields.Genres))
{
dto.Genres = item.Genres;
+ AttachGenreItems(dto, item);
}
if (options.EnableImages)
@@ -1130,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
@@ -1179,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
@@ -1449,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;
@@ -1582,24 +1595,30 @@ namespace Emby.Server.Implementations.Dto
ImageSize size;
- if (supportedEnhancers.Count == 0)
- {
- var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
+ var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
- if (defaultAspectRatio.HasValue)
+ if (defaultAspectRatio.HasValue)
+ {
+ if (supportedEnhancers.Count == 0)
{
return defaultAspectRatio.Value;
}
- }
- try
- {
- size = _imageProcessor.GetImageSize(imageInfo);
+ double dummyWidth = 200;
+ double dummyHeight = dummyWidth / defaultAspectRatio.Value;
+ size = new ImageSize(dummyWidth, dummyHeight);
}
- catch
+ else
{
- //_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
- return null;
+ try
+ {
+ size = _imageProcessor.GetImageSize(imageInfo);
+ }
+ catch
+ {
+ //_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
+ return null;
+ }
}
foreach (var enhancer in supportedEnhancers)
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index b2f1f0ceb..14d976325 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -10,9 +10,8 @@
<RootNamespace>Emby.Server.Implementations</RootNamespace>
<AssemblyName>Emby.Server.Implementations</AssemblyName>
<FileAlignment>512</FileAlignment>
- <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
- <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <TargetFrameworkProfile />
+ <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -103,6 +102,7 @@
<Compile Include="HttpServer\SocketSharp\WebSocketSharpResponse.cs" />
<Compile Include="HttpServer\StreamWriter.cs" />
<Compile Include="Images\BaseDynamicImageProvider.cs" />
+ <Compile Include="IO\AsyncStreamCopier.cs" />
<Compile Include="IO\FileRefresher.cs" />
<Compile Include="IO\MbLinkShortcutHandler.cs" />
<Compile Include="IO\ThrottledStream.cs" />
@@ -182,7 +182,6 @@
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\LibraryScanMigration.cs" />
<Compile Include="Migrations\GuideMigration.cs" />
- <Compile Include="Migrations\UpdateLevelMigration.cs" />
<Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="News\NewsService.cs" />
<Compile Include="Notifications\CoreNotificationTypes.cs" />
@@ -291,9 +290,9 @@
<Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
<Name>MediaBrowser.Server.Implementations</Name>
</ProjectReference>
- <ProjectReference Include="..\SocketHttpListener.Portable\SocketHttpListener.Portable.csproj">
- <Project>{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}</Project>
- <Name>SocketHttpListener.Portable</Name>
+ <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
+ <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
+ <Name>SocketHttpListener</Name>
</ProjectReference>
<Reference Include="Emby.XmlTv, Version=1.0.6299.28292, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Emby.XmlTv.1.0.8\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
@@ -313,6 +312,17 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
<EmbeddedResource Include="Localization\Core\ar.json" />
<EmbeddedResource Include="Localization\Core\bg-BG.json" />
<EmbeddedResource Include="Localization\Core\ca.json" />
@@ -410,7 +420,7 @@
<ItemGroup>
<EmbeddedResource Include="Localization\Ratings\uk.txt" />
</ItemGroup>
- <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index b93410180..71e31d4d4 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.EntryPoints
.DistinctBy(i => i.Id)
.Select(i =>
{
- var dto = _userDataManager.GetUserDataDto(i, user).Result;
+ var dto = _userDataManager.GetUserDataDto(i, user);
dto.ItemId = i.Id.ToString("N");
return dto;
})
diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 86c8c5f68..cf9fdbb16 100644
--- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -15,7 +15,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Library;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
@@ -588,7 +588,8 @@ namespace Emby.Server.Implementations.FileOrganization
var series = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Series).Name },
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(true)
})
.Cast<Series>()
.Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
@@ -607,7 +608,8 @@ namespace Emby.Server.Implementations.FileOrganization
{
IncludeItemTypes = new[] { typeof(Series).Name },
Recursive = true,
- Name = info.ItemName
+ Name = info.ItemName,
+ DtoOptions = new DtoOptions(true)
}).Cast<Series>().FirstOrDefault();
}
diff --git a/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs b/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs
index 4094e6b9b..d95bd8734 100644
--- a/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs
+++ b/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs
@@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Events;
using MediaBrowser.Common.Events;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Tasks;
diff --git a/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
index 5be7ba7ad..b71a3975f 100644
--- a/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
+++ b/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
@@ -8,7 +8,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
diff --git a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
index 2cbf2613e..0dbd6f837 100644
--- a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
+++ b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
@@ -10,7 +10,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
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/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 0af88595f..6c37d5f7a 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -58,6 +58,18 @@ namespace Emby.Server.Implementations.HttpServer
return GetHttpResult(content, contentType, true, responseHeaders);
}
+ public object GetRedirectResult(string url)
+ {
+ var responseHeaders = new Dictionary<string, string>();
+ responseHeaders["Location"] = url;
+
+ var result = new HttpResult(new byte[] { }, "text/plain", HttpStatusCode.Redirect);
+
+ AddResponseHeaders(result, responseHeaders);
+
+ return result;
+ }
+
/// <summary>
/// Gets the HTTP result.
/// </summary>
@@ -599,9 +611,9 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- private async Task<IHasHeaders> GetCompressedResult(Stream stream,
- string requestedCompressionType,
- IDictionary<string,string> responseHeaders,
+ private async Task<IHasHeaders> GetCompressedResult(Stream stream,
+ string requestedCompressionType,
+ IDictionary<string, string> responseHeaders,
bool isHeadRequest,
string contentType)
{
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..e648838b2 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;
@@ -33,6 +34,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private readonly bool _enableDualMode;
private readonly IEnvironmentInfo _environment;
+ private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
+ private CancellationToken _disposeCancellationToken;
+
public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
@@ -47,10 +51,12 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_httpRequestFactory = httpRequestFactory;
_fileSystem = fileSystem;
_environment = environment;
+
+ _disposeCancellationToken = _disposeCancellationTokenSource.Token;
}
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; }
@@ -81,11 +87,11 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private void ProcessContext(HttpListenerContext context)
{
- //Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness);
- Task.Run(() => InitTask(context));
+ InitTask(context, _disposeCancellationToken);
+ //Task.Run(() => InitTask(context, _disposeCancellationToken));
}
- private Task InitTask(HttpListenerContext context)
+ private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
{
IHttpRequest httpReq = null;
var request = context.Request;
@@ -111,7 +117,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)
@@ -172,6 +178,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Stop()
{
+ _disposeCancellationTokenSource.Cancel();
+
if (_listener != null)
{
foreach (var prefix in _listener.Prefixes.ToList())
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
index b3fcde745..2dfe6a9e3 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Net;
using System.Text;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
@@ -374,7 +373,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
this.pathInfo = request.RawUrl;
}
- this.pathInfo = WebUtility.UrlDecode(pathInfo);
+ this.pathInfo = System.Net.WebUtility.UrlDecode(pathInfo);
this.pathInfo = NormalizePathInfo(pathInfo, mode);
}
return this.pathInfo;
@@ -440,7 +439,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
cookies = new Dictionary<string, System.Net.Cookie>();
foreach (var cookie in this.request.Cookies)
{
- var httpCookie = (Cookie) cookie;
+ var httpCookie = (System.Net.Cookie) cookie;
cookies[httpCookie.Name] = new System.Net.Cookie(httpCookie.Name, httpCookie.Value, httpCookie.Path, httpCookie.Domain);
}
}
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index 9e58ee57c..d6762d94b 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -114,15 +114,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
var outputStream = response.OutputStream;
// This is needed with compression
- if (outputStream is ResponseStream)
- {
- //if (!string.IsNullOrWhiteSpace(GetHeader("Content-Encoding")))
- {
- outputStream.Flush();
- }
+ outputStream.Flush();
+ outputStream.Dispose();
- outputStream.Dispose();
- }
response.Close();
}
catch (Exception ex)
diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
index 33378949c..5d42f42fa 100644
--- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
@@ -5,7 +5,7 @@ using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.Services;
namespace Emby.Server.Implementations.HttpServer
diff --git a/Emby.Server.Implementations/IO/AsyncStreamCopier.cs b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs
new file mode 100644
index 000000000..9e5ce0604
--- /dev/null
+++ b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs
@@ -0,0 +1,459 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Emby.Server.Implementations.IO
+{
+ public class AsyncStreamCopier : IDisposable
+ {
+ // size in bytes of the buffers in the buffer pool
+ private const int DefaultBufferSize = 81920;
+ private readonly int _bufferSize;
+ // number of buffers in the pool
+ private const int DefaultBufferCount = 4;
+ private readonly int _bufferCount;
+
+ // indexes of the next buffer to read into/write from
+ private int _nextReadBuffer = -1;
+ private int _nextWriteBuffer = -1;
+
+ // the buffer pool, implemented as an array, and used in a cyclic way
+ private readonly byte[][] _buffers;
+ // sizes in bytes of the available (read) data in the buffers
+ private readonly int[] _sizes;
+ // the streams...
+ private Stream _source;
+ private Stream _target;
+ private readonly bool _closeStreamsOnEnd;
+
+ // number of buffers that are ready to be written
+ private int _buffersToWrite;
+ // flag indicating that there is still a read operation to be scheduled
+ // (source end of stream not reached)
+ private volatile bool _moreDataToRead;
+ // the result of the whole operation, returned by BeginCopy()
+ private AsyncResult _asyncResult;
+ // any exception that occurs during an async operation
+ // stored here for rethrow
+ private Exception _exception;
+
+ public TaskCompletionSource<long> TaskCompletionSource;
+ private long _bytesToRead;
+ private long _totalBytesWritten;
+ private CancellationToken _cancellationToken;
+ public int IndividualReadOffset = 0;
+
+ public AsyncStreamCopier(Stream source,
+ Stream target,
+ long bytesToRead,
+ CancellationToken cancellationToken,
+ bool closeStreamsOnEnd = false,
+ int bufferSize = DefaultBufferSize,
+ int bufferCount = DefaultBufferCount)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ if (target == null)
+ throw new ArgumentNullException("target");
+ if (!source.CanRead)
+ throw new ArgumentException("Cannot copy from a non-readable stream.");
+ if (!target.CanWrite)
+ throw new ArgumentException("Cannot copy to a non-writable stream.");
+ _source = source;
+ _target = target;
+ _moreDataToRead = true;
+ _closeStreamsOnEnd = closeStreamsOnEnd;
+ _bufferSize = bufferSize;
+ _bufferCount = bufferCount;
+ _buffers = new byte[_bufferCount][];
+ _sizes = new int[_bufferCount];
+ _bytesToRead = bytesToRead;
+ _cancellationToken = cancellationToken;
+ }
+
+ ~AsyncStreamCopier()
+ {
+ // ensure any exception cannot be ignored
+ ThrowExceptionIfNeeded();
+ }
+
+ public static Task<long> CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, CancellationToken cancellationToken)
+ {
+ return CopyStream(source, target, 0, bufferSize, bufferCount, cancellationToken);
+ }
+
+ public static Task<long> CopyStream(Stream source, Stream target, long size, int bufferSize, int bufferCount, CancellationToken cancellationToken)
+ {
+ var copier = new AsyncStreamCopier(source, target, size, cancellationToken, false, bufferSize, bufferCount);
+ var taskCompletion = new TaskCompletionSource<long>();
+
+ copier.TaskCompletionSource = taskCompletion;
+
+ var result = copier.BeginCopy(StreamCopyCallback, copier);
+
+ if (result.CompletedSynchronously)
+ {
+ StreamCopyCallback(result);
+ }
+
+ cancellationToken.Register(() => taskCompletion.TrySetCanceled());
+
+ return taskCompletion.Task;
+ }
+
+ private static void StreamCopyCallback(IAsyncResult result)
+ {
+ var copier = (AsyncStreamCopier)result.AsyncState;
+ var taskCompletion = copier.TaskCompletionSource;
+
+ try
+ {
+ copier.EndCopy(result);
+ taskCompletion.TrySetResult(copier._totalBytesWritten);
+ }
+ catch (Exception ex)
+ {
+ taskCompletion.TrySetException(ex);
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_asyncResult != null)
+ _asyncResult.Dispose();
+ if (_closeStreamsOnEnd)
+ {
+ if (_source != null)
+ {
+ _source.Dispose();
+ _source = null;
+ }
+ if (_target != null)
+ {
+ _target.Dispose();
+ _target = null;
+ }
+ }
+ GC.SuppressFinalize(this);
+ ThrowExceptionIfNeeded();
+ }
+
+ public IAsyncResult BeginCopy(AsyncCallback callback, object state)
+ {
+ // avoid concurrent start of the copy on separate threads
+ if (Interlocked.CompareExchange(ref _asyncResult, new AsyncResult(callback, state), null) != null)
+ throw new InvalidOperationException("A copy operation has already been started on this object.");
+ // allocate buffers
+ for (int i = 0; i < _bufferCount; i++)
+ _buffers[i] = new byte[_bufferSize];
+
+ // we pass false to BeginRead() to avoid completing the async result
+ // immediately which would result in invoking the callback
+ // when the method fails synchronously
+ BeginRead(false);
+ // throw exception synchronously if there is one
+ ThrowExceptionIfNeeded();
+ return _asyncResult;
+ }
+
+ public void EndCopy(IAsyncResult ar)
+ {
+ if (ar != _asyncResult)
+ throw new InvalidOperationException("Invalid IAsyncResult object.");
+
+ if (!_asyncResult.IsCompleted)
+ _asyncResult.AsyncWaitHandle.WaitOne();
+
+ if (_closeStreamsOnEnd)
+ {
+ _source.Close();
+ _source = null;
+ _target.Close();
+ _target = null;
+ }
+
+ //_logger.Info("AsyncStreamCopier {0} bytes requested. {1} bytes transferred", _bytesToRead, _totalBytesWritten);
+ ThrowExceptionIfNeeded();
+ }
+
+ /// <summary>
+ /// Here we'll throw a pending exception if there is one,
+ /// and remove it from our instance, so we know it has been consumed.
+ /// </summary>
+ private void ThrowExceptionIfNeeded()
+ {
+ if (_exception != null)
+ {
+ var exception = _exception;
+ _exception = null;
+ throw exception;
+ }
+ }
+
+ private void BeginRead(bool completeOnError = true)
+ {
+ if (!_moreDataToRead)
+ {
+ return;
+ }
+ if (_asyncResult.IsCompleted)
+ return;
+ int bufferIndex = Interlocked.Increment(ref _nextReadBuffer) % _bufferCount;
+
+ try
+ {
+ _source.BeginRead(_buffers[bufferIndex], 0, _bufferSize, EndRead, bufferIndex);
+ }
+ catch (Exception exception)
+ {
+ _exception = exception;
+ if (completeOnError)
+ _asyncResult.Complete(false);
+ }
+ }
+
+ private void BeginWrite()
+ {
+ if (_asyncResult.IsCompleted)
+ return;
+ // this method can actually be called concurrently!!
+ // indeed, let's say we call a BeginWrite, and the thread gets interrupted
+ // just after making the IO request.
+ // At that moment, the thread is still in the method. And then the IO request
+ // ends (extremely fast io, or caching...), EndWrite gets called
+ // on another thread, and calls BeginWrite again! There we have it!
+ // That is the reason why an Interlocked is needed here.
+ int bufferIndex = Interlocked.Increment(ref _nextWriteBuffer) % _bufferCount;
+
+ try
+ {
+ int bytesToWrite;
+ if (_bytesToRead > 0)
+ {
+ var bytesLeftToWrite = _bytesToRead - _totalBytesWritten;
+ bytesToWrite = Convert.ToInt32(Math.Min(_sizes[bufferIndex], bytesLeftToWrite));
+ }
+ else
+ {
+ bytesToWrite = _sizes[bufferIndex];
+ }
+
+ _target.BeginWrite(_buffers[bufferIndex], IndividualReadOffset, bytesToWrite - IndividualReadOffset, EndWrite, null);
+
+ _totalBytesWritten += bytesToWrite;
+ }
+ catch (Exception exception)
+ {
+ _exception = exception;
+ _asyncResult.Complete(false);
+ }
+ }
+
+ private void EndRead(IAsyncResult ar)
+ {
+ try
+ {
+ int read = _source.EndRead(ar);
+ _moreDataToRead = read > 0;
+ var bufferIndex = (int)ar.AsyncState;
+ _sizes[bufferIndex] = read;
+ }
+ catch (Exception exception)
+ {
+ _exception = exception;
+ _asyncResult.Complete(false);
+ return;
+ }
+
+ if (_moreDataToRead && !_cancellationToken.IsCancellationRequested)
+ {
+ int usedBuffers = Interlocked.Increment(ref _buffersToWrite);
+ // if we incremented from zero to one, then it means we just
+ // added the single buffer to write, so a writer could not
+ // be busy, and we have to schedule one.
+ if (usedBuffers == 1)
+ BeginWrite();
+ // test if there is at least a free buffer, and schedule
+ // a read, as we have read some data
+ if (usedBuffers < _bufferCount)
+ BeginRead();
+ }
+ else
+ {
+ // we did not add a buffer, because no data was read, and
+ // there is no buffer left to write so this is the end...
+ if (Thread.VolatileRead(ref _buffersToWrite) == 0)
+ {
+ _asyncResult.Complete(false);
+ }
+ }
+ }
+
+ private void EndWrite(IAsyncResult ar)
+ {
+ try
+ {
+ _target.EndWrite(ar);
+ }
+ catch (Exception exception)
+ {
+ _exception = exception;
+ _asyncResult.Complete(false);
+ return;
+ }
+
+ int buffersLeftToWrite = Interlocked.Decrement(ref _buffersToWrite);
+ // no reader could be active if all buffers were full of data waiting to be written
+ bool noReaderIsBusy = buffersLeftToWrite == _bufferCount - 1;
+ // note that it is possible that both a reader and
+ // a writer see the end of the copy and call Complete
+ // on the _asyncResult object. That race condition is handled by
+ // Complete that ensures it is only executed fully once.
+
+ long bytesLeftToWrite;
+ if (_bytesToRead > 0)
+ {
+ bytesLeftToWrite = _bytesToRead - _totalBytesWritten;
+ }
+ else
+ {
+ bytesLeftToWrite = 1;
+ }
+
+ if (!_moreDataToRead || bytesLeftToWrite <= 0 || _cancellationToken.IsCancellationRequested)
+ {
+ // at this point we know no reader can schedule a read or write
+ if (Thread.VolatileRead(ref _buffersToWrite) == 0)
+ {
+ // nothing left to write, so it is the end
+ _asyncResult.Complete(false);
+ return;
+ }
+ }
+ else
+ // here, we know we have something left to read,
+ // so schedule a read if no read is busy
+ if (noReaderIsBusy)
+ BeginRead();
+
+ // also schedule a write if we are sure we did not write the last buffer
+ // note that if buffersLeftToWrite is zero and a reader has put another
+ // buffer to write between the time we decremented _buffersToWrite
+ // and now, that reader will also schedule another write,
+ // as it will increment _buffersToWrite from zero to one
+ if (buffersLeftToWrite > 0)
+ BeginWrite();
+ }
+ }
+
+ internal class AsyncResult : IAsyncResult, IDisposable
+ {
+ // Fields set at construction which never change while
+ // operation is pending
+ private readonly AsyncCallback _asyncCallback;
+ private readonly object _asyncState;
+
+ // Fields set at construction which do change after
+ // operation completes
+ private const int StatePending = 0;
+ private const int StateCompletedSynchronously = 1;
+ private const int StateCompletedAsynchronously = 2;
+ private int _completedState = StatePending;
+
+ // Field that may or may not get set depending on usage
+ private ManualResetEvent _waitHandle;
+
+ internal AsyncResult(
+ AsyncCallback asyncCallback,
+ object state)
+ {
+ _asyncCallback = asyncCallback;
+ _asyncState = state;
+ }
+
+ internal bool Complete(bool completedSynchronously)
+ {
+ bool result = false;
+
+ // The _completedState field MUST be set prior calling the callback
+ int prevState = Interlocked.CompareExchange(ref _completedState,
+ completedSynchronously ? StateCompletedSynchronously :
+ StateCompletedAsynchronously, StatePending);
+ if (prevState == StatePending)
+ {
+ // If the event exists, set it
+ if (_waitHandle != null)
+ _waitHandle.Set();
+
+ if (_asyncCallback != null)
+ _asyncCallback(this);
+
+ result = true;
+ }
+
+ return result;
+ }
+
+ #region Implementation of IAsyncResult
+
+ public Object AsyncState { get { return _asyncState; } }
+
+ public bool CompletedSynchronously
+ {
+ get
+ {
+ return Thread.VolatileRead(ref _completedState) ==
+ StateCompletedSynchronously;
+ }
+ }
+
+ public WaitHandle AsyncWaitHandle
+ {
+ get
+ {
+ if (_waitHandle == null)
+ {
+ bool done = IsCompleted;
+ var mre = new ManualResetEvent(done);
+ if (Interlocked.CompareExchange(ref _waitHandle,
+ mre, null) != null)
+ {
+ // Another thread created this object's event; dispose
+ // the event we just created
+ mre.Close();
+ }
+ else
+ {
+ if (!done && IsCompleted)
+ {
+ // If the operation wasn't done when we created
+ // the event but now it is done, set the event
+ _waitHandle.Set();
+ }
+ }
+ }
+ return _waitHandle;
+ }
+ }
+
+ public bool IsCompleted
+ {
+ get
+ {
+ return Thread.VolatileRead(ref _completedState) !=
+ StatePending;
+ }
+ }
+ #endregion
+
+ public void Dispose()
+ {
+ if (_waitHandle != null)
+ {
+ _waitHandle.Dispose();
+ _waitHandle = null;
+ }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index edff25156..9606b60b8 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -6,7 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Events;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
@@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.IO
try
{
- await item.ChangedExternally().ConfigureAwait(false);
+ item.ChangedExternally();
}
catch (IOException ex)
{
@@ -231,7 +231,7 @@ namespace Emby.Server.Implementations.IO
private bool IsFileLocked(string path)
{
- if (_environmentInfo.OperatingSystem != OperatingSystem.Windows)
+ if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
{
// Causing lockups on linux
return false;
@@ -282,11 +282,11 @@ namespace Emby.Server.Implementations.IO
return false;
}
}
- //catch (DirectoryNotFoundException)
- //{
- // // File may have been deleted
- // return false;
- //}
+ catch (DirectoryNotFoundException)
+ {
+ // File may have been deleted
+ return false;
+ }
catch (FileNotFoundException)
{
// File may have been deleted
diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
index 0b1391ae0..aef53751e 100644
--- a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
+++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
@@ -1,6 +1,6 @@
using System;
using System.IO;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index b2ec84a82..b8ce23a42 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -12,7 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.IO;
@@ -59,33 +59,6 @@ namespace Emby.Server.Implementations.Images
//return GetSupportedImages(item).Where(i => IsEnabled(options, i, item)).ToList();
}
- private bool IsEnabled(MetadataOptions options, ImageType type, IHasImages item)
- {
- if (type == ImageType.Backdrop)
- {
- if (item.LockedFields.Contains(MetadataFields.Backdrops))
- {
- return false;
- }
- }
- else if (type == ImageType.Screenshot)
- {
- if (item.LockedFields.Contains(MetadataFields.Screenshots))
- {
- return false;
- }
- }
- else
- {
- if (item.LockedFields.Contains(MetadataFields.Images))
- {
- return false;
- }
- }
-
- return options.IsEnabled(type);
- }
-
public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
if (!Supports(item))
@@ -128,7 +101,7 @@ namespace Emby.Server.Implementations.Images
}
}
- var items = await GetItemsWithImages(item).ConfigureAwait(false);
+ var items = GetItemsWithImages(item);
return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
}
@@ -140,7 +113,7 @@ namespace Emby.Server.Implementations.Images
{
var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N"));
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPathWithoutExtension));
- string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false);
+ string outputPath = CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0);
if (string.IsNullOrWhiteSpace(outputPath))
{
@@ -159,9 +132,9 @@ namespace Emby.Server.Implementations.Images
return ItemUpdateType.ImageUpdate;
}
- protected abstract Task<List<BaseItem>> GetItemsWithImages(IHasImages item);
+ protected abstract List<BaseItem> GetItemsWithImages(IHasImages item);
- protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 640, 360);
}
@@ -188,22 +161,22 @@ namespace Emby.Server.Implementations.Images
.Where(i => !string.IsNullOrWhiteSpace(i));
}
- protected Task<string> CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 400, 600);
}
- protected Task<string> CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 600, 600);
}
- protected Task<string> CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
return CreateCollage(primaryItem, items, outputPath, width, height);
}
- private async Task<string> CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ private string CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
@@ -225,7 +198,7 @@ namespace Emby.Server.Implementations.Images
return null;
}
- await ImageProcessor.CreateImageCollage(options).ConfigureAwait(false);
+ ImageProcessor.CreateImageCollage(options);
return outputPath;
}
@@ -234,7 +207,7 @@ namespace Emby.Server.Implementations.Images
get { return "Dynamic Image Provider"; }
}
- protected virtual async Task<string> CreateImage(IHasImages item,
+ protected virtual string CreateImage(IHasImages item,
List<BaseItem> itemsWithImages,
string outputPathWithoutExtension,
ImageType imageType,
@@ -249,20 +222,20 @@ namespace Emby.Server.Implementations.Images
if (imageType == ImageType.Thumb)
{
- return await CreateThumbCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
+ return CreateThumbCollage(item, itemsWithImages, outputPath);
}
if (imageType == ImageType.Primary)
{
if (item is UserView)
{
- return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
+ return CreateSquareCollage(item, itemsWithImages, outputPath);
}
if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
{
- return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
+ return CreateSquareCollage(item, itemsWithImages, outputPath);
}
- return await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
+ return CreatePosterCollage(item, itemsWithImages, outputPath);
}
throw new ArgumentException("Unexpected image type");
@@ -346,7 +319,7 @@ namespace Emby.Server.Implementations.Images
}
}
- protected async Task<string> CreateSingleImage(List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType)
+ protected string CreateSingleImage(List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType)
{
var image = itemsWithImages
.Where(i => i.HasImage(imageType) && i.GetImageInfo(imageType, 0).IsLocalFile && Path.HasExtension(i.GetImagePath(imageType)))
diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
index 64f025d93..54f9ca392 100644
--- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 3c94f9784..42eda00b7 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -40,7 +40,8 @@ using MediaBrowser.Model.Net;
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
using VideoResolver = MediaBrowser.Naming.Video.VideoResolver;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
+
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Tasks;
@@ -313,7 +314,8 @@ namespace Emby.Server.Implementations.Library
{
IncludeItemTypes = new[] { typeof(Season).Name },
Recursive = true,
- IndexNumber = 0
+ IndexNumber = 0,
+ DtoOptions = new DtoOptions(true)
}).Cast<Season>()
.Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal))
@@ -342,7 +344,7 @@ namespace Emby.Server.Implementations.Library
}
if (item is IItemByName)
{
- if (!(item is MusicArtist) && !(item is Studio))
+ if (!(item is MusicArtist))
{
return;
}
@@ -862,13 +864,19 @@ namespace Emby.Server.Implementations.Library
// If this returns multiple items it could be tricky figuring out which one is correct.
// In most cases, the newest one will be and the others obsolete but not yet cleaned up
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
var query = new InternalItemsQuery
{
Path = path,
IsFolder = isFolder,
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending,
- Limit = 1
+ Limit = 1,
+ DtoOptions = new DtoOptions(true)
};
return GetItemList(query)
@@ -882,7 +890,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>
@@ -892,7 +900,27 @@ 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)
+ {
+ return GetItemByNameId<Studio>(Studio.GetPath, name);
+ }
+
+ public Guid GetGenreId(string name)
+ {
+ return GetItemByNameId<Genre>(Genre.GetPath, name);
+ }
+
+ public Guid GetMusicGenreId(string name)
+ {
+ return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name);
+ }
+
+ public Guid GetGameGenreId(string name)
+ {
+ return GetItemByNameId<GameGenre>(GameGenre.GetPath, name);
}
/// <summary>
@@ -902,7 +930,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>
@@ -912,7 +940,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>
@@ -922,7 +950,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>
@@ -940,7 +968,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>
@@ -950,10 +978,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));
+ }
+
+ public MusicArtist GetArtist(string name, DtoOptions options)
+ {
+ return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name, options);
}
- private T CreateItemByName<T>(Func<string, string> getPathFn, string name)
+ private T CreateItemByName<T>(Func<string, string> getPathFn, string name, DtoOptions options)
where T : BaseItem, new()
{
if (typeof(T) == typeof(MusicArtist))
@@ -961,7 +994,8 @@ namespace Emby.Server.Implementations.Library
var existing = GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(T).Name },
- Name = name
+ Name = name,
+ DtoOptions = options
}).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
@@ -974,14 +1008,13 @@ namespace Emby.Server.Implementations.Library
}
}
- var path = getPathFn(name);
- var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
- var id = GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
+ var id = GetItemByNameId<T>(getPathFn, name);
var item = GetItemById(id) as T;
if (item == null)
{
+ var path = getPathFn(name);
item = new T
{
Name = name,
@@ -998,52 +1031,12 @@ namespace Emby.Server.Implementations.Library
return item;
}
- 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)
+ private Guid GetItemByNameId<T>(Func<string, string> getPathFn, string name)
+ where T : BaseItem, new()
{
- 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;
+ var path = getPathFn(name);
+ var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
+ return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
/// <summary>
@@ -1098,12 +1091,6 @@ namespace Emby.Server.Implementations.Library
try
{
await PerformLibraryValidation(progress, cancellationToken).ConfigureAwait(false);
-
- if (!ConfigurationManager.Configuration.EnableSeriesPresentationUniqueKey)
- {
- ConfigurationManager.Configuration.EnableSeriesPresentationUniqueKey = true;
- ConfigurationManager.SaveConfiguration();
- }
}
finally
{
@@ -1558,7 +1545,7 @@ namespace Emby.Server.Implementations.Library
}
}
- query.ParentId = null;
+ query.Parent = null;
}
private void AddUserToQuery(InternalItemsQuery query, User user)
diff --git a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
index 7424ed5e5..e64980dff 100644
--- a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
@@ -6,6 +6,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -27,7 +28,8 @@ namespace Emby.Server.Implementations.Library
var items = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name },
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(true)
}).OfType<IHasTrailers>().ToList();
@@ -40,7 +42,8 @@ namespace Emby.Server.Implementations.Library
{
IncludeItemTypes = new[] { typeof(Trailer).Name },
TrailerTypes = trailerTypes,
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(false)
}).ToArray();
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index b15c01125..f0d07cc3c 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Playlists;
using System;
using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Library
@@ -18,47 +19,48 @@ namespace Emby.Server.Implementations.Library
_libraryManager = libraryManager;
}
- public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user)
+ public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
{
var list = new List<Audio>
{
item
};
- return list.Concat(GetInstantMixFromGenres(item.Genres, user));
+ return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions));
}
- public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist item, User user)
+ public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
{
- return GetInstantMixFromGenres(item.Genres, user);
+ return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user)
+ public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
{
- return GetInstantMixFromGenres(item.Genres, user);
+ return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user)
+ public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
{
var genres = item
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { typeof(Audio).Name }
+ IncludeItemTypes = new[] { typeof(Audio).Name },
+ DtoOptions = dtoOptions
})
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)
.DistinctNames();
- return GetInstantMixFromGenres(genres, user);
+ return GetInstantMixFromGenres(genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user)
+ public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
{
- return GetInstantMixFromGenres(item.Genres, user);
+ return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user)
+ public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
{
var genreIds = genres.DistinctNames().Select(i =>
{
@@ -73,10 +75,10 @@ namespace Emby.Server.Implementations.Library
}).Where(i => i != null);
- return GetInstantMixFromGenreIds(genreIds, user);
+ return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user)
+ public IEnumerable<Audio> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
@@ -86,47 +88,49 @@ namespace Emby.Server.Implementations.Library
Limit = 200,
- SortBy = new[] { ItemSortBy.Random }
+ SortBy = new[] { ItemSortBy.Random },
+
+ DtoOptions = dtoOptions
}).Cast<Audio>();
}
- public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user)
+ public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
{
var genre = item as MusicGenre;
if (genre != null)
{
- return GetInstantMixFromGenreIds(new[] { item.Id.ToString("N") }, user);
+ return GetInstantMixFromGenreIds(new[] { item.Id.ToString("N") }, user, dtoOptions);
}
var playlist = item as Playlist;
if (playlist != null)
{
- return GetInstantMixFromPlaylist(playlist, user);
+ return GetInstantMixFromPlaylist(playlist, user, dtoOptions);
}
var album = item as MusicAlbum;
if (album != null)
{
- return GetInstantMixFromAlbum(album, user);
+ return GetInstantMixFromAlbum(album, user, dtoOptions);
}
var artist = item as MusicArtist;
if (artist != null)
{
- return GetInstantMixFromArtist(artist, user);
+ return GetInstantMixFromArtist(artist, user, dtoOptions);
}
var song = item as Audio;
if (song != null)
{
- return GetInstantMixFromSong(song, user);
+ return GetInstantMixFromSong(song, user, dtoOptions);
}
var folder = item as Folder;
if (folder != null)
{
- return GetInstantMixFromFolder(folder, user);
+ return GetInstantMixFromFolder(folder, user, dtoOptions);
}
return new Audio[] { };
diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs
index 1d3cacc1d..24dc1104a 100644
--- a/Emby.Server.Implementations/Library/ResolverHelper.cs
+++ b/Emby.Server.Implementations/Library/ResolverHelper.cs
@@ -5,8 +5,6 @@ using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index b3d6d4ad7..806e20f00 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Naming.Audio;
using System;
using System.Collections.Generic;
using System.IO;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 2971405b9..2ad839673 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 3550a83b9..69563e5a0 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -11,7 +11,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
index 1bec1073d..6c7c1f052 100644
--- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Resolvers;
using System;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index e5cad9f91..60260e98a 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -10,7 +10,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index 5f88a6c66..6f63322c8 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Extensions;
namespace Emby.Server.Implementations.Library
@@ -175,7 +176,17 @@ namespace Emby.Server.Implementations.Library
IsNews = query.IsNews,
IsSeries = query.IsSeries,
IsSports = query.IsSports,
- MediaTypes = query.MediaTypes
+ MediaTypes = query.MediaTypes,
+
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<ItemFields>
+ {
+ ItemFields.AirTime,
+ ItemFields.DateCreated,
+ ItemFields.ChannelInfo
+ }
+ }
});
// Add search hints based on item name
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index 5a14edf13..e066ab61b 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -182,21 +182,21 @@ namespace Emby.Server.Implementations.Library
return GetUserData(userId, item.Id, item.GetUserDataKeys());
}
- public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user)
+ public UserItemDataDto GetUserDataDto(IHasUserData item, User user)
{
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- await item.FillUserDataDtoValues(dto, userData, null, user, new List<ItemFields>()).ConfigureAwait(false);
+ item.FillUserDataDtoValues(dto, userData, null, user, new List<ItemFields>());
return dto;
}
- public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields)
+ public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields)
{
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- await item.FillUserDataDtoValues(dto, userData, itemDto, user, fields).ConfigureAwait(false);
+ item.FillUserDataDtoValues(dto, userData, itemDto, user, fields);
return dto;
}
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index 9e1291847..f403ca266 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Globalization;
@@ -190,11 +191,11 @@ namespace Emby.Server.Implementations.Library
return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
}
- public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
+ public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options)
{
var user = _userManager.GetUserById(request.UserId);
- var libraryItems = GetItemsForLatestItems(user, request);
+ var libraryItems = GetItemsForLatestItems(user, request, options);
var list = new List<Tuple<BaseItem, List<BaseItem>>>();
@@ -230,7 +231,7 @@ namespace Emby.Server.Implementations.Library
return list;
}
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request)
+ private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
{
var parentId = request.ParentId;
@@ -289,7 +290,8 @@ namespace Emby.Server.Implementations.Library
IsVirtualItem = false,
Limit = limit * 5,
SourceTypes = parents.Count == 0 ? new[] { SourceType.Library } : new SourceType[] { },
- IsPlayed = isPlayed
+ IsPlayed = isPlayed,
+ DtoOptions = options
}, parents);
}
diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
index 7ebfd71c0..ef3b86abf 100644
--- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -11,7 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index ef440899c..dcfaaa9d7 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -3,9 +3,10 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging;
@@ -29,7 +30,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return targetFile;
}
- public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ public Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ {
+ if (directStreamProvider != null)
+ {
+ return RecordFromDirectStreamProvider(directStreamProvider, targetFile, duration, onStarted, cancellationToken);
+ }
+
+ return RecordFromMediaSource(mediaSource, targetFile, duration, onStarted, cancellationToken);
+ }
+
+ private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ {
+ using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
+ {
+ onStarted();
+
+ _logger.Info("Copying recording stream to file {0}", targetFile);
+
+ // The media source if infinite so we need to handle stopping ourselves
+ var durationToken = new CancellationTokenSource(duration);
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+
+ await directStreamProvider.CopyToAsync(output, cancellationToken).ConfigureAwait(false);
+ }
+
+ _logger.Info("Recording completed to file {0}", targetFile);
+ }
+
+ private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
var httpRequestOptions = new HttpRequestOptions
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index f1b3f41b4..6ce2b88f1 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -28,8 +28,9 @@ using System.Xml;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
@@ -1232,7 +1233,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
RequiresClosing = false,
Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
BufferMs = 0,
- IgnoreDts = true
+ IgnoreDts = true,
+ IgnoreIndex = true
};
var isAudio = false;
@@ -1517,7 +1519,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
EnforceKeepUpTo(timer, seriesPath);
};
- await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
+ await recorder.Record(liveStreamInfo.Item1 as IDirectStreamProvider, mediaStreamInfo, recordPath, duration, onStarted, cancellationToken).ConfigureAwait(false);
recordingStatus = RecordingStatus.Completed;
_logger.Info("Recording completed: {0}", recordPath);
@@ -1634,15 +1636,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return;
}
- var episodesToDelete = (await librarySeries.GetItems(new InternalItemsQuery
+ var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery
{
SortBy = new[] { ItemSortBy.DateCreated },
SortOrder = SortOrder.Descending,
IsVirtualItem = false,
IsFolder = false,
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(true)
- }).ConfigureAwait(false))
+ }))
.Items
.Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
.Skip(seriesTimer.KeepUpTo - 1)
@@ -1759,20 +1762,30 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var config = GetConfiguration();
- if (config.EnableRecordingEncoding)
- {
- var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
+ var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
- if (regInfo.IsValid)
+ if (regInfo.IsValid)
+ {
+ if (config.EnableRecordingEncoding)
{
return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, config, _httpClient, _processFactory, _config);
}
+
+ return new DirectRecorder(_logger, _httpClient, _fileSystem);
+
+ //var options = new LiveTvOptions
+ //{
+ // EnableOriginalAudioWithEncodedRecordings = true,
+ // RecordedVideoCodec = "copy",
+ // RecordingEncodingFormat = "ts"
+ //};
+ //return new EncodedRecorder(_logger, _fileSystem, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, options, _httpClient, _processFactory, _config);
}
- return new DirectRecorder(_logger, _httpClient, _fileSystem);
+ throw new InvalidOperationException("Emby DVR Requires an active Emby Premiere subscription.");
}
- private async void OnSuccessfulRecording(TimerInfo timer, string path)
+ private void OnSuccessfulRecording(TimerInfo timer, string path)
{
//if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize)
//{
@@ -1967,7 +1980,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
Limit = 1,
- ExternalId = timer.ProgramId
+ ExternalId = timer.ProgramId,
+ DtoOptions = new DtoOptions(true)
}).FirstOrDefault() as LiveTvProgram;
@@ -2501,16 +2515,17 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (program.EpisodeNumber.HasValue && program.SeasonNumber.HasValue)
{
- var result = _libraryManager.GetItemsResult(new InternalItemsQuery
+ var result = _libraryManager.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Episode).Name },
ParentIndexNumber = program.SeasonNumber.Value,
IndexNumber = program.EpisodeNumber.Value,
AncestorIds = seriesIds,
- IsVirtualItem = false
+ IsVirtualItem = false,
+ Limit = 1
});
- if (result.TotalRecordCount > 0)
+ if (result.Count > 0)
{
return true;
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 790e6c27d..6173068cc 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -8,7 +8,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -21,6 +21,7 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Library;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
@@ -64,6 +65,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
return "mkv";
}
+ if (string.Equals(format, "ts", StringComparison.OrdinalIgnoreCase))
+ {
+ return "ts";
+ }
return "mp4";
}
@@ -90,7 +95,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return Path.ChangeExtension(targetFile, "." + extension);
}
- public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ public async Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
//var durationToken = new CancellationTokenSource(duration);
//cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
@@ -177,6 +182,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
videoArgs = "-codec:v:0 copy";
}
+ videoArgs += " -fflags +genpts";
+
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var flags = new List<string>();
@@ -188,28 +195,37 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
flags.Add("+ignidx");
}
+ if (mediaSource.GenPtsInput)
+ {
+ flags.Add("+genpts");
+ }
- var inputModifiers = "-async 1 -vsync -1";
+ var inputModifier = "-async 1 -vsync -1";
if (flags.Count > 0)
{
- inputModifiers += " -fflags " + string.Join("", flags.ToArray());
+ inputModifier += " -fflags " + string.Join("", flags.ToArray());
}
if (!string.IsNullOrWhiteSpace(GetEncodingOptions().HardwareAccelerationType))
{
- inputModifiers += " -hwaccel auto";
+ inputModifier += " -hwaccel auto";
}
if (mediaSource.ReadAtNativeFramerate)
{
- inputModifiers += " -re";
+ inputModifier += " -re";
+ }
+
+ if (mediaSource.RequiresLooping)
+ {
+ inputModifier += " -stream_loop -1";
}
var analyzeDurationSeconds = 5;
var analyzeDuration = " -analyzeduration " +
(analyzeDurationSeconds * 1000000).ToString(CultureInfo.InvariantCulture);
- inputModifiers += analyzeDuration;
+ inputModifier += analyzeDuration;
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
@@ -228,7 +244,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
durationParam,
outputParam);
- return inputModifiers + " " + commandLineArgs;
+ return inputModifier + " " + commandLineArgs;
}
private string GetAudioArgs(MediaSourceInfo mediaSource)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
index 3b5e60c4a..e639a312c 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
@@ -10,13 +11,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
/// <summary>
/// Records the specified media source.
/// </summary>
- /// <param name="mediaSource">The media source.</param>
- /// <param name="targetFile">The target file.</param>
- /// <param name="duration">The duration.</param>
- /// <param name="onStarted">The on started.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
+ Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken);
string GetOutputPath(MediaSourceInfo mediaSource, string targetFile);
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 953cb8e41..4ba2269a6 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -4,7 +4,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 17de93a3c..94be4a02e 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
else
{
- name += " " + info.StartDate.ToString("yyyy-MM-dd") + " " + info.Id;
+ name += " " + info.StartDate.ToString("yyyy-MM-dd");
}
return name;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
index 7bf6bf1ca..843ba7e42 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
@@ -2,8 +2,6 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 2eec3df8a..380b24800 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -8,7 +8,7 @@ using System.Collections.Concurrent;
using System.Globalization;
using System.Linq;
using System.Threading;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index a36cb124d..da6759b34 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -167,10 +167,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var programEntry = programDict[schedule.programID];
- var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
- data = data.OrderByDescending(GetSizeOrder).ToList();
+ var allImages = (images[imageIndex].data ?? new List<ScheduleDirect.ImageData>()).OrderByDescending(GetSizeOrder).ToList();
+ var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList();
+
+ programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, "Logo", true, 600) ??
+ GetProgramImage(ApiUrl, allImages, "Logo", true, 600);
- programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600);
//programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 43b055098..5c5072192 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -149,7 +149,11 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(Series).Name },
Name = seriesName,
Limit = 1,
- ImageTypes = new ImageType[] { ImageType.Thumb }
+ ImageTypes = new ImageType[] { ImageType.Thumb },
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
+ }
}).FirstOrDefault();
@@ -191,7 +195,11 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ExternalSeriesId = programSeriesId,
Limit = 1,
- ImageTypes = new ImageType[] { ImageType.Primary }
+ ImageTypes = new ImageType[] { ImageType.Primary },
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
+ }
}).FirstOrDefault();
@@ -239,7 +247,11 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(Series).Name },
Name = seriesName,
Limit = 1,
- ImageTypes = new ImageType[] { ImageType.Thumb }
+ ImageTypes = new ImageType[] { ImageType.Thumb },
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
+ }
}).FirstOrDefault();
@@ -281,14 +293,22 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(Series).Name },
Name = seriesName,
Limit = 1,
- ImageTypes = new ImageType[] { ImageType.Primary }
+ ImageTypes = new ImageType[] { ImageType.Primary },
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
+ }
}).FirstOrDefault() ?? _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ExternalSeriesId = programSeriesId,
Limit = 1,
- ImageTypes = new ImageType[] { ImageType.Primary }
+ ImageTypes = new ImageType[] { ImageType.Primary },
+ DtoOptions = new DtoOptions
+ {
+ Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
+ }
}).FirstOrDefault();
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index fa86ac36d..c2f057560 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -26,7 +26,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Events;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Common.Security;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -173,7 +173,7 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
+ public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@@ -192,7 +192,8 @@ namespace Emby.Server.Implementations.LiveTv
IsFavorite = query.IsFavorite,
IsLiked = query.IsLiked,
StartIndex = query.StartIndex,
- Limit = query.Limit
+ Limit = query.Limit,
+ DtoOptions = dtoOptions
};
internalQuery.OrderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending)));
@@ -249,7 +250,7 @@ namespace Emby.Server.Implementations.LiveTv
{
Id = id
- }, cancellationToken).ConfigureAwait(false);
+ }, new DtoOptions(), cancellationToken).ConfigureAwait(false);
return result.Items.FirstOrDefault();
}
@@ -477,7 +478,8 @@ 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
+ // 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.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams)
@@ -864,13 +866,6 @@ namespace Emby.Server.Implementations.LiveTv
return item.Id;
}
-
-
- private string GetExternalSeriesIdLegacy(BaseItem item)
- {
- return item.GetProviderId("ProviderExternalSeriesId");
- }
-
public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
{
var program = GetInternalProgram(id);
@@ -881,11 +876,6 @@ namespace Emby.Server.Implementations.LiveTv
var externalSeriesId = program.ExternalSeriesId;
- if (string.IsNullOrWhiteSpace(externalSeriesId))
- {
- externalSeriesId = GetExternalSeriesIdLegacy(program);
- }
-
list.Add(new Tuple<BaseItemDto, string, string, string>(dto, program.ServiceName, GetItemExternalId(program), externalSeriesId));
await AddRecordingInfo(list, cancellationToken).ConfigureAwait(false);
@@ -905,6 +895,8 @@ namespace Emby.Server.Implementations.LiveTv
query.SortBy = new[] { ItemSortBy.StartDate };
}
+ RemoveFields(options);
+
var internalQuery = new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
@@ -964,8 +956,6 @@ namespace Emby.Server.Implementations.LiveTv
var queryResult = _libraryManager.QueryItems(internalQuery);
- RemoveFields(options);
-
var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
@@ -1044,12 +1034,12 @@ namespace Emby.Server.Implementations.LiveTv
public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
{
+ RemoveFields(options);
+
var internalResult = await GetRecommendedProgramsInternal(query, options, cancellationToken).ConfigureAwait(false);
var user = _userManager.GetUserById(query.UserId);
- RemoveFields(options);
-
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
var result = new QueryResult<BaseItemDto>
@@ -1332,7 +1322,8 @@ namespace Emby.Server.Implementations.LiveTv
{
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
- ChannelIds = new string[] { currentChannel.Id.ToString("N") }
+ ChannelIds = new string[] { currentChannel.Id.ToString("N") },
+ DtoOptions = new DtoOptions(true)
}).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
@@ -1435,7 +1426,8 @@ namespace Emby.Server.Implementations.LiveTv
{
var list = _itemRepo.GetItemIdsList(new InternalItemsQuery
{
- IncludeItemTypes = validTypes
+ IncludeItemTypes = validTypes,
+ DtoOptions = new DtoOptions(false)
}).ToList();
@@ -1662,6 +1654,8 @@ namespace Emby.Server.Implementations.LiveTv
includeItemTypes.Add(typeof(Series).Name);
+ RemoveFields(options);
+
var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
Recursive = true,
@@ -1671,11 +1665,10 @@ namespace Emby.Server.Implementations.LiveTv
SortOrder = SortOrder.Descending,
EnableTotalRecordCount = query.EnableTotalRecordCount,
IncludeItemTypes = includeItemTypes.ToArray(),
- ExcludeItemTypes = excludeItemTypes.ToArray()
+ ExcludeItemTypes = excludeItemTypes.ToArray(),
+ DtoOptions = options
});
- RemoveFields(options);
-
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
return new QueryResult<BaseItemDto>
@@ -1685,7 +1678,7 @@ namespace Emby.Server.Implementations.LiveTv
};
}
- public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
+ public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
if (user != null && !IsLiveTvEnabled(user))
@@ -1695,14 +1688,15 @@ namespace Emby.Server.Implementations.LiveTv
if (_services.Count == 1 && !(query.IsInProgress ?? false) && (!query.IsLibraryItem.HasValue || query.IsLibraryItem.Value))
{
- return GetEmbyRecordings(query, new DtoOptions(), user);
+ return GetEmbyRecordings(query, options, user);
}
await RefreshRecordings(cancellationToken).ConfigureAwait(false);
var internalQuery = new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }
+ IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name },
+ DtoOptions = options
};
if (!string.IsNullOrEmpty(query.ChannelId))
@@ -1871,11 +1865,6 @@ namespace Emby.Server.Implementations.LiveTv
var externalSeriesId = program.ExternalSeriesId;
- if (string.IsNullOrWhiteSpace(externalSeriesId))
- {
- externalSeriesId = GetExternalSeriesIdLegacy(program);
- }
-
programTuples.Add(new Tuple<BaseItemDto, string, string, string>(dto, serviceName, GetItemExternalId(program), externalSeriesId));
}
@@ -1952,10 +1941,10 @@ namespace Emby.Server.Implementations.LiveTv
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
- var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false);
-
RemoveFields(options);
+ var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
+
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
return new QueryResult<BaseItemDto>
@@ -2298,7 +2287,8 @@ namespace Emby.Server.Implementations.LiveTv
MinEndDate = now,
Limit = channelIds.Length,
SortBy = new[] { "StartDate" },
- TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }
+ TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") },
+ DtoOptions = options
}).ToList() : new List<BaseItem>();
@@ -2600,7 +2590,7 @@ namespace Emby.Server.Implementations.LiveTv
{
UserId = query.UserId
- }, cancellationToken).ConfigureAwait(false);
+ }, new DtoOptions(), cancellationToken).ConfigureAwait(false);
var recordings = recordingResult.Items.OfType<ILiveTvRecording>().ToList();
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index d724a9fbc..504f9a6ee 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -421,7 +421,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsDirectStream = true,
SupportsTranscoding = true,
IsInfiniteStream = true,
- IgnoreDts = true
+ IgnoreDts = true,
+ //IgnoreIndex = true,
+ ReadAtNativeFramerate = true
};
mediaSource.InferTotalBitrate();
@@ -505,12 +507,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 == MediaBrowser.Model.System.OperatingSystem.OSX
+ || _environment.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.BSD;
enableHttpStream = true;
if (enableHttpStream)
{
@@ -519,17 +521,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)
@@ -596,10 +597,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Need a way to set the Receive timeout on the socket otherwise this might never timeout?
try
{
- await udpClient.SendAsync(discBytes, discBytes.Length, new IpEndPointInfo(new IpAddressInfo("255.255.255.255", IpAddressFamily.InterNetwork), 65001), cancellationToken);
+ await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IpEndPointInfo(new IpAddressInfo("255.255.255.255", IpAddressFamily.InterNetwork), 65001), cancellationToken);
+ var receiveBuffer = new byte[8192];
+
while (!cancellationToken.IsCancellationRequested)
{
- var response = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ var response = await udpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
var deviceIp = response.RemoteEndPoint.IpAddress.Address;
// check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
index 2798805fa..5db842dec 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
@@ -2,6 +2,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -10,6 +11,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 +19,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)
@@ -57,9 +57,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
- OpenedMediaSource.SupportsDirectPlay = false;
- OpenedMediaSource.SupportsDirectStream = true;
- OpenedMediaSource.SupportsTranscoding = true;
+ //OpenedMediaSource.SupportsDirectPlay = false;
+ //OpenedMediaSource.SupportsDirectStream = true;
+ //OpenedMediaSource.SupportsTranscoding = true;
await taskCompletionSource.Task.ConfigureAwait(false);
@@ -74,9 +74,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 +101,14 @@ 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))
{
- onStarted = () => openTaskCompletionSource.TrySetResult(true);
- }
+ ResolveAfterDelay(3000, openTaskCompletionSource);
- await _multicastStream.CopyUntilCancelled(response.Content, onStarted, cancellationToken).ConfigureAwait(false);
+ //await response.Content.CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false);
+ await AsyncStreamCopier.CopyStream(response.Content, fileStream, 81920, 4, cancellationToken).ConfigureAwait(false);
+ }
}
}
}
@@ -131,13 +132,60 @@ 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);
+ return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
+ }
+
+ 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);
+ }
+
+ using (var inputStream = GetInputStream(path, startPosition, true))
+ {
+ if (startPosition > 0)
+ {
+ inputStream.Position = startPosition;
+ }
+
+ while (eofCount < 20 || !allowEndOfFile)
+ {
+ var bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 4, 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;
+ }
+ }
+ }
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 2c678d9f8..41b058baf 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;
}
@@ -103,8 +114,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var ipEndPoint = new IpEndPointInfo(remoteIp, HdHomeRunPort);
var lockkeyMsg = CreateGetMessage(tuner, "lockkey");
- await socket.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken);
- var response = await socket.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ await socket.SendToAsync(lockkeyMsg, 0, lockkeyMsg.Length, ipEndPoint, cancellationToken);
+
+ var receiveBuffer = new byte[8192];
+ var response = await socket.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
+
string returnVal;
ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal);
@@ -117,6 +131,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
{
+ var receiveBuffer = new byte[8192];
+
if (!_lockkey.HasValue)
{
var rand = new Random();
@@ -133,8 +149,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_activeTuner = i;
var lockKeyString = String.Format("{0:d}", _lockkey.Value);
var lockkeyMsg = CreateSetMessage(i, "lockkey", lockKeyString, null);
- await tcpClient.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
- var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(lockkeyMsg, 0, lockkeyMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+ var response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
string returnVal;
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
@@ -144,8 +160,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
foreach(Tuple<string,string> command in commandList)
{
var channelMsg = CreateSetMessage(i, command.Item1, command.Item2, _lockkey.Value);
- await tcpClient.SendAsync(channelMsg, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
- response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+ response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
{
@@ -158,8 +174,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var targetValue = String.Format("rtp://{0}:{1}", localIp, localPort);
var targetMsg = CreateSetMessage(i, "target", targetValue, _lockkey.Value);
- await tcpClient.SendAsync(targetMsg, targetMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
- response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(targetMsg, 0, targetMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+ response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
{
@@ -180,11 +196,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
{
var commandList = commands.GetCommands();
+ var receiveBuffer = new byte[8192];
+
foreach (Tuple<string, string> command in commandList)
{
var channelMsg = CreateSetMessage(_activeTuner, command.Item1, command.Item2, _lockkey.Value);
- await tcpClient.SendAsync(channelMsg, channelMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
- var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
+ var response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
string returnVal;
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
@@ -209,12 +227,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private async Task ReleaseLockkey(ISocket tcpClient)
{
var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", _lockkey);
- await tcpClient.SendAsync(releaseTarget, releaseTarget.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
- await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
+ await tcpClient.SendToAsync(releaseTarget, 0, releaseTarget.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
+
+ var receiveBuffer = new byte[8192];
+
+ await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, CancellationToken.None).ConfigureAwait(false);
var releaseKeyMsg = CreateSetMessage(_activeTuner, "lockkey", "none", _lockkey);
_lockkey = null;
- await tcpClient.SendAsync(releaseKeyMsg, releaseKeyMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
- await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
+ await tcpClient.SendToAsync(releaseKeyMsg, 0, releaseKeyMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
+ await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, CancellationToken.None).ConfigureAwait(false);
}
private static byte[] CreateGetMessage(int tuner, string name)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index e1572ea3f..2989177c0 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Library;
@@ -14,39 +15,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)
@@ -70,9 +67,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
- OpenedMediaSource.SupportsDirectPlay = false;
- OpenedMediaSource.SupportsDirectStream = true;
- OpenedMediaSource.SupportsTranscoding = true;
+ //OpenedMediaSource.SupportsDirectPlay = false;
+ //OpenedMediaSource.SupportsDirectStream = true;
+ //OpenedMediaSource.SupportsTranscoding = true;
await taskCompletionSource.Task.ConfigureAwait(false);
@@ -87,9 +84,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 +121,11 @@ 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))
{
- onStarted = () => openTaskCompletionSource.TrySetResult(true);
+ await CopyTo(udpClient, fileStream, openTaskCompletionSource, cancellationToken).ConfigureAwait(false);
}
-
- await _multicastStream.CopyUntilCancelled(new UdpClientStream(udpClient), onStarted, cancellationToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException ex)
@@ -159,135 +154,109 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- }).ConfigureAwait(false);
+ await DeleteTempFile(_tempFilePath).ConfigureAwait(false);
+ });
}
- public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
+ private void Resolve(TaskCompletionSource<bool> openTaskCompletionSource)
{
- return _multicastStream.CopyToAsync(stream);
+ Task.Run(() =>
+ {
+ openTaskCompletionSource.TrySetResult(true);
+ });
}
- }
-
- // This handles the ReadAsync function only of a Stream object
- // This is used to wrap a UDP socket into a stream for MulticastStream which only uses ReadAsync
- public class UdpClientStream : Stream
- {
- private static int RtpHeaderBytes = 12;
- private static int PacketSize = 1316;
- private readonly ISocket _udpClient;
- bool disposed;
- public UdpClientStream(ISocket udpClient) : base()
+ public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- _udpClient = udpClient;
+ return CopyFileTo(_tempFilePath, false, stream, cancellationToken);
}
- public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken)
{
- if (buffer == null)
- throw new ArgumentNullException("buffer");
+ var eofCount = 0;
- if (offset + count < 0)
- throw new ArgumentOutOfRangeException("offset + count must not be negative", "offset+count");
+ long startPosition = -25000;
+ if (startPosition < 0)
+ {
+ var length = FileSystem.GetFileInfo(path).Length;
+ startPosition = Math.Max(length - startPosition, 0);
+ }
- if (offset + count > buffer.Length)
- throw new ArgumentException("offset + count must not be greater than the length of buffer", "offset+count");
+ using (var inputStream = GetInputStream(path, startPosition, true))
+ {
+ if (startPosition > 0)
+ {
+ inputStream.Position = startPosition;
+ }
- if (disposed)
- throw new ObjectDisposedException(typeof(UdpClientStream).ToString());
+ while (eofCount < 20 || !allowEndOfFile)
+ {
+ var bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 4, cancellationToken).ConfigureAwait(false);
- // 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;
- int totalBytesRead = 0;
+ //var position = fs.Position;
+ //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
- for (int i = 0; i < numReads; ++i)
- {
- 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;
- totalBytesRead += bytesRead;
+ if (bytesRead == 0)
+ {
+ eofCount++;
+ await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ eofCount = 0;
+ }
+ }
}
- return totalBytesRead;
}
- protected override void Dispose(bool disposing)
+ private static int RtpHeaderBytes = 12;
+ private Task CopyTo(ISocket udpClient, Stream outputStream, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
- disposed = true;
+ return CopyStream(_socketFactory.CreateNetworkStream(udpClient, false), outputStream, 81920, 4, openTaskCompletionSource, cancellationToken);
}
- public override bool CanRead
+ private Task CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
- get
- {
- throw new NotImplementedException();
- }
- }
+ var copier = new AsyncStreamCopier(source, target, 0, cancellationToken, false, bufferSize, bufferCount);
+ copier.IndividualReadOffset = RtpHeaderBytes;
- public override bool CanSeek
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ var taskCompletion = new TaskCompletionSource<long>();
- public override bool CanWrite
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ copier.TaskCompletionSource = taskCompletion;
- public override long Length
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ var result = copier.BeginCopy(StreamCopyCallback, copier);
- public override long Position
- {
- get
+ if (openTaskCompletionSource != null)
{
- throw new NotImplementedException();
+ Resolve(openTaskCompletionSource);
+ openTaskCompletionSource = null;
}
- set
+ if (result.CompletedSynchronously)
{
- throw new NotImplementedException();
+ StreamCopyCallback(result);
}
- }
- public override void Flush()
- {
- throw new NotImplementedException();
- }
+ cancellationToken.Register(() => taskCompletion.TrySetCanceled());
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
+ return taskCompletion.Task;
}
- public override long Seek(long offset, SeekOrigin origin)
+ private void StreamCopyCallback(IAsyncResult result)
{
- throw new NotImplementedException();
- }
+ var copier = (AsyncStreamCopier)result.AsyncState;
+ var taskCompletion = copier.TaskCompletionSource;
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
+ try
+ {
+ copier.EndCopy(result);
+ taskCompletion.TrySetResult(0);
+ }
+ catch (Exception ex)
+ {
+ taskCompletion.TrySetException(ex);
+ }
}
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 8cf1106f0..12b7901f9 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -11,7 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -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/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 8c4b9bf60..4c1190e0e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -8,7 +8,6 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.IO;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
index 02ebbcf16..e650086d3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -15,7 +15,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
private readonly ConcurrentDictionary<Guid,QueueStream> _outputStreams = new ConcurrentDictionary<Guid, QueueStream>();
private const int BufferSize = 81920;
- private CancellationToken _cancellationToken;
private readonly ILogger _logger;
public MulticastStream(ILogger logger)
@@ -25,8 +24,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
{
- _cancellationToken = cancellationToken;
-
byte[] buffer = new byte[BufferSize];
if (source == null)
@@ -72,59 +69,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
}
- private static int RtpHeaderBytes = 12;
- public async Task CopyUntilCancelled(ISocket udpClient, Action onStarted, CancellationToken cancellationToken)
- {
- _cancellationToken = cancellationToken;
-
- while (!cancellationToken.IsCancellationRequested)
- {
- var receiveToken = cancellationToken;
-
- // On the first connection attempt, put a timeout to avoid being stuck indefinitely in the event of failure
- if (onStarted != null)
- {
- receiveToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(5000).Token, cancellationToken).Token;
- }
-
- var data = await udpClient.ReceiveAsync(receiveToken).ConfigureAwait(false);
- var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
-
- if (bytesRead > 0)
- {
- var allStreams = _outputStreams.ToList();
-
- if (allStreams.Count == 1)
- {
- await allStreams[0].Value.WriteAsync(data.Buffer, 0, bytesRead).ConfigureAwait(false);
- }
- else
- {
- byte[] copy = new byte[bytesRead];
- Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, copy, 0, bytesRead);
-
- foreach (var stream in allStreams)
- {
- stream.Value.Queue(copy, 0, copy.Length);
- }
- }
-
- if (onStarted != null)
- {
- var onStartedCopy = onStarted;
- onStarted = null;
- Task.Run(onStartedCopy);
- }
- }
-
- else
- {
- await Task.Delay(100).ConfigureAwait(false);
- }
- }
- }
-
- public Task CopyToAsync(Stream stream)
+ public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
var result = new QueueStream(stream, _logger)
{
@@ -133,7 +78,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
_outputStreams.TryAdd(result.Id, result);
- result.Start(_cancellationToken);
+ result.Start(cancellationToken);
return result.TaskCompletion.Task;
}
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index 884a001f0..1d74e8788 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -13,7 +13,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Library;
diff --git a/Emby.Server.Implementations/Migrations/GuideMigration.cs b/Emby.Server.Implementations/Migrations/GuideMigration.cs
index 99b2942dc..78fb6c222 100644
--- a/Emby.Server.Implementations/Migrations/GuideMigration.cs
+++ b/Emby.Server.Implementations/Migrations/GuideMigration.cs
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Migrations
_taskManager = taskManager;
}
- public async Task Run()
+ public Task Run()
{
var name = "GuideRefresh3";
@@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.Migrations
_config.Configuration.Migrations = list.ToArray();
_config.SaveConfiguration();
}
+
+ return Task.FromResult(true);
}
}
}
diff --git a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs b/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs
index bd185bc9c..9d7f67a4f 100644
--- a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs
+++ b/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Migrations
_taskManager = taskManager;
}
- public async Task Run()
+ public Task Run()
{
var name = "LibraryScan6";
@@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.Migrations
_config.Configuration.Migrations = list.ToArray();
_config.SaveConfiguration();
}
+
+ return Task.FromResult(true);
}
}
}
diff --git a/Emby.Server.Implementations/Migrations/UpdateLevelMigration.cs b/Emby.Server.Implementations/Migrations/UpdateLevelMigration.cs
deleted file mode 100644
index c532ea08d..000000000
--- a/Emby.Server.Implementations/Migrations/UpdateLevelMigration.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Updates;
-
-namespace Emby.Server.Implementations.Migrations
-{
- public class UpdateLevelMigration : IVersionMigration
- {
- private readonly IServerConfigurationManager _config;
- private readonly IServerApplicationHost _appHost;
- private readonly IHttpClient _httpClient;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly string _releaseAssetFilename;
- private readonly ILogger _logger;
-
- public UpdateLevelMigration(IServerConfigurationManager config, IServerApplicationHost appHost, IHttpClient httpClient, IJsonSerializer jsonSerializer, string releaseAssetFilename, ILogger logger)
- {
- _config = config;
- _appHost = appHost;
- _httpClient = httpClient;
- _jsonSerializer = jsonSerializer;
- _releaseAssetFilename = releaseAssetFilename;
- _logger = logger;
- }
-
- public async Task Run()
- {
- var lastVersion = _config.Configuration.LastVersion;
- var currentVersion = _appHost.ApplicationVersion;
-
- if (string.Equals(lastVersion, currentVersion.ToString(), StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- try
- {
- var updateLevel = _config.Configuration.SystemUpdateLevel;
-
- await CheckVersion(currentVersion, updateLevel, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in update migration", ex);
- }
- }
-
- private async Task CheckVersion(Version currentVersion, PackageVersionClass currentUpdateLevel, CancellationToken cancellationToken)
- {
- var releases = await new GithubUpdater(_httpClient, _jsonSerializer)
- .GetLatestReleases("MediaBrowser", "Emby", _releaseAssetFilename, cancellationToken).ConfigureAwait(false);
-
- var newUpdateLevel = GetNewUpdateLevel(currentVersion, currentUpdateLevel, releases);
-
- if (newUpdateLevel != currentUpdateLevel)
- {
- _config.Configuration.SystemUpdateLevel = newUpdateLevel;
- _config.SaveConfiguration();
- }
- }
-
- private PackageVersionClass GetNewUpdateLevel(Version currentVersion, PackageVersionClass currentUpdateLevel, List<GithubUpdater.RootObject> releases)
- {
- var newUpdateLevel = currentUpdateLevel;
-
- // If the current version is later than current stable, set the update level to beta
- if (releases.Count >= 1)
- {
- var release = releases[0];
- var version = ParseVersion(release.tag_name);
- if (version != null)
- {
- if (currentVersion > version)
- {
- newUpdateLevel = PackageVersionClass.Beta;
- }
- else
- {
- return PackageVersionClass.Release;
- }
- }
- }
-
- // If the current version is later than current beta, set the update level to dev
- if (releases.Count >= 2)
- {
- var release = releases[1];
- var version = ParseVersion(release.tag_name);
- if (version != null)
- {
- if (currentVersion > version)
- {
- newUpdateLevel = PackageVersionClass.Dev;
- }
- else
- {
- return PackageVersionClass.Beta;
- }
- }
- }
-
- return newUpdateLevel;
- }
-
- private Version ParseVersion(string versionString)
- {
- if (!string.IsNullOrWhiteSpace(versionString))
- {
- var parts = versionString.Split('.');
- if (parts.Length == 3)
- {
- versionString += ".0";
- }
- }
-
- Version version;
- Version.TryParse(versionString, out version);
-
- return version;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
index cc1756f96..0744fc0d9 100644
--- a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
+++ b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
@@ -18,15 +18,15 @@ namespace Emby.Server.Implementations.Photos
{
}
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var photoAlbum = (PhotoAlbum)item;
var items = GetFinalItems(photoAlbum.Children.ToList());
- return Task.FromResult(items);
+ return items;
}
- protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
index 9514c12ca..127ce24ae 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -10,7 +10,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Emby.Server.Implementations.Images;
-using MediaBrowser.Common.IO;
+
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
@@ -26,7 +27,7 @@ namespace Emby.Server.Implementations.Playlists
{
}
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var playlist = (Playlist)item;
@@ -67,7 +68,7 @@ namespace Emby.Server.Implementations.Playlists
.DistinctBy(i => i.Id)
.ToList();
- return Task.FromResult(GetFinalItems(items));
+ return GetFinalItems(items);
}
}
@@ -80,7 +81,7 @@ namespace Emby.Server.Implementations.Playlists
_libraryManager = libraryManager;
}
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery
{
@@ -89,11 +90,12 @@ namespace Emby.Server.Implementations.Playlists
SortBy = new[] { ItemSortBy.Random },
Limit = 4,
Recursive = true,
- ImageTypes = new[] { ImageType.Primary }
+ ImageTypes = new[] { ImageType.Primary },
+ DtoOptions = new DtoOptions(false)
}).ToList();
- return Task.FromResult(GetFinalItems(items));
+ return GetFinalItems(items);
}
//protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
@@ -111,7 +113,7 @@ namespace Emby.Server.Implementations.Playlists
_libraryManager = libraryManager;
}
- protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery
{
@@ -120,11 +122,12 @@ namespace Emby.Server.Implementations.Playlists
SortBy = new[] { ItemSortBy.Random },
Limit = 4,
Recursive = true,
- ImageTypes = new[] { ImageType.Primary }
+ ImageTypes = new[] { ImageType.Primary },
+ DtoOptions = new DtoOptions(false)
}).ToList();
- return Task.FromResult(GetFinalItems(items));
+ return GetFinalItems(items);
}
//protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 18042b587..e0e133e38 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -12,7 +12,8 @@ using System.IO;
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;
@@ -135,7 +136,10 @@ namespace Emby.Server.Implementations.Playlists
if (options.ItemIdList.Count > 0)
{
- await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user);
+ await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user, new DtoOptions(false)
+ {
+ EnableImages = true
+ });
}
return new PlaylistCreationResult
@@ -160,21 +164,24 @@ namespace Emby.Server.Implementations.Playlists
return path;
}
- private Task<IEnumerable<BaseItem>> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user)
+ private IEnumerable<BaseItem> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user, DtoOptions options)
{
var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null);
- return Playlist.GetPlaylistItems(playlistMediaType, items, user);
+ return Playlist.GetPlaylistItems(playlistMediaType, items, user, options);
}
public Task AddToPlaylist(string playlistId, IEnumerable<string> itemIds, string userId)
{
var user = string.IsNullOrWhiteSpace(userId) ? null : _userManager.GetUserById(userId);
- return AddToPlaylistInternal(playlistId, itemIds, user);
+ return AddToPlaylistInternal(playlistId, itemIds, user, new DtoOptions(false)
+ {
+ EnableImages = true
+ });
}
- private async Task AddToPlaylistInternal(string playlistId, IEnumerable<string> itemIds, User user)
+ private async Task AddToPlaylistInternal(string playlistId, IEnumerable<string> itemIds, User user, DtoOptions options)
{
var playlist = _libraryManager.GetItemById(playlistId) as Playlist;
@@ -185,12 +192,17 @@ namespace Emby.Server.Implementations.Playlists
var list = new List<LinkedChild>();
- var items = (await GetPlaylistItems(itemIds, playlist.MediaType, user).ConfigureAwait(false))
+ var items = (GetPlaylistItems(itemIds, playlist.MediaType, user, options))
.Where(i => i.SupportsAddingToPlaylist)
.ToList();
foreach (var item in items)
{
+ if (string.IsNullOrWhiteSpace(item.Path))
+ {
+ continue;
+ }
+
list.Add(LinkedChild.Create(item));
}
@@ -271,7 +283,7 @@ namespace Emby.Server.Implementations.Playlists
{
var typeName = "PlaylistsFolder";
- return _libraryManager.RootFolder.Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal)) ??
+ return _libraryManager.RootFolder.Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal)) ??
_libraryManager.GetUserRootFolder().Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal));
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index d1c70ba1d..967e7ddd8 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -10,7 +10,7 @@ using System.IO;
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.Entities;
@@ -85,7 +85,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
MediaTypes = new[] { MediaType.Video },
IsFolder = false,
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(false)
+
})
.OfType<Video>()
.ToList();
diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs b/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
index 749233fa1..9bf6f2824 100644
--- a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs
@@ -4,7 +4,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
diff --git a/Emby.Server.Implementations/ServerManager/ServerManager.cs b/Emby.Server.Implementations/ServerManager/ServerManager.cs
index 4c9228e54..7cd94c526 100644
--- a/Emby.Server.Implementations/ServerManager/ServerManager.cs
+++ b/Emby.Server.Implementations/ServerManager/ServerManager.cs
@@ -12,7 +12,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
+
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Text;
diff --git a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
index ac20fe7b3..e4392d7e6 100644
--- a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
@@ -9,7 +9,6 @@ using System.Collections.Specialized;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Text;
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 3c2af60db..84dc343c3 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -12,43 +12,28 @@ namespace Emby.Server.Implementations.Services
{
public static class ResponseHelper
{
- public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result)
+ public static async Task WriteToResponse(IResponse response, IRequest request, object result, CancellationToken cancellationToken)
{
if (result == null)
{
- if (httpRes.StatusCode == (int)HttpStatusCode.OK)
+ if (response.StatusCode == (int)HttpStatusCode.OK)
{
- httpRes.StatusCode = (int)HttpStatusCode.NoContent;
+ response.StatusCode = (int)HttpStatusCode.NoContent;
}
- httpRes.SetContentLength(0);
- return Task.FromResult(true);
+ response.SetContentLength(0);
+ return;
}
var httpResult = result as IHttpResult;
if (httpResult != null)
{
- httpResult.RequestContext = httpReq;
- httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType;
- return WriteToResponseInternal(httpRes, httpResult, httpReq);
+ httpResult.RequestContext = request;
+ request.ResponseContentType = httpResult.ContentType ?? request.ResponseContentType;
}
- return WriteToResponseInternal(httpRes, result, httpReq);
- }
-
- /// <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)
- {
var defaultContentType = request.ResponseContentType;
- var httpResult = result as IHttpResult;
if (httpResult != null)
{
if (httpResult.RequestContext == null)
@@ -105,7 +90,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 +104,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;
}
@@ -139,7 +124,7 @@ namespace Emby.Server.Implementations.Services
response.ContentType = "application/octet-stream";
response.SetContentLength(bytes.Length);
- await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
return;
}
@@ -148,7 +133,7 @@ namespace Emby.Server.Implementations.Services
{
bytes = Encoding.UTF8.GetBytes(responseText);
response.SetContentLength(bytes.Length);
- await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
return;
}
diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs
index d283bf81f..1c530144c 100644
--- a/Emby.Server.Implementations/Services/ServiceController.cs
+++ b/Emby.Server.Implementations/Services/ServiceController.cs
@@ -187,7 +187,7 @@ namespace Emby.Server.Implementations.Services
return null;
}
- public async Task<object> Execute(HttpListenerHost appHost, object requestDto, IRequest req)
+ public Task<object> Execute(HttpListenerHost appHost, object requestDto, IRequest req)
{
req.Dto = requestDto;
var requestType = requestDto.GetType();
@@ -209,9 +209,7 @@ namespace Emby.Server.Implementations.Services
req.Dto = requestDto;
//Executes the service and returns the result
- var response = await ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName()).ConfigureAwait(false);
-
- return response;
+ return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
}
}
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index 8b59b4843..526e62d39 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)
@@ -142,7 +143,8 @@ namespace Emby.Server.Implementations.Services
var rawResponse = await appHost.ServiceController.Execute(appHost, request, httpReq).ConfigureAwait(false);
- var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
+ //var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
+ var response = rawResponse;
// Apply response filters
foreach (var responseFilter in appHost.ResponseFilters)
@@ -150,7 +152,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/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs
index 2acc3902f..92fa6c424 100644
--- a/Emby.Server.Implementations/Session/HttpSessionController.cs
+++ b/Emby.Server.Implementations/Session/HttpSessionController.cs
@@ -66,19 +66,19 @@ namespace Emby.Server.Implementations.Session
return SendMessage(name, new Dictionary<string, string>(), cancellationToken);
}
- private async Task SendMessage(string name,
+ private Task SendMessage(string name,
Dictionary<string, string> args,
CancellationToken cancellationToken)
{
var url = PostUrl + "/" + name + ToQueryString(args);
- await _httpClient.Post(new HttpRequestOptions
+ return _httpClient.Post(new HttpRequestOptions
{
Url = url,
CancellationToken = cancellationToken,
BufferContent = false
- }).ConfigureAwait(false);
+ });
}
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
@@ -159,8 +159,24 @@ namespace Emby.Server.Implementations.Session
public Task SendMessage<T>(string name, T data, CancellationToken cancellationToken)
{
- // Not supported or needed right now
- return Task.FromResult(true);
+ var url = PostUrl + "/" + name;
+
+ var options = new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = cancellationToken,
+ BufferContent = false
+ };
+
+ options.RequestContent = _json.SerializeToString(data);
+ options.RequestContentType = "application/json";
+
+ return _httpClient.Post(new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = cancellationToken,
+ BufferContent = false
+ });
}
private string ToQueryString(Dictionary<string, string> nvc)
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index de00cf239..42cd5d1b1 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -30,6 +30,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Threading;
namespace Emby.Server.Implementations.Session
@@ -984,7 +985,7 @@ namespace Emby.Server.Implementations.Session
var list = new List<BaseItem>();
foreach (var itemId in command.ItemIds)
{
- var subItems = await TranslateItemForPlayback(itemId, user).ConfigureAwait(false);
+ var subItems = TranslateItemForPlayback(itemId, user);
list.AddRange(subItems);
}
@@ -1022,7 +1023,10 @@ namespace Emby.Server.Implementations.Session
var series = episode.Series;
if (series != null)
{
- var episodes = series.GetEpisodes(user)
+ var episodes = series.GetEpisodes(user, new DtoOptions(false)
+ {
+ EnableImages = false
+ })
.Where(i => !i.IsVirtualItem)
.SkipWhile(i => i.Id != episode.Id)
.ToList();
@@ -1048,7 +1052,7 @@ namespace Emby.Server.Implementations.Session
await session.SessionController.SendPlayCommand(command, cancellationToken).ConfigureAwait(false);
}
- private async Task<List<BaseItem>> TranslateItemForPlayback(string id, User user)
+ private List<BaseItem> TranslateItemForPlayback(string id, User user)
{
var item = _libraryManager.GetItemById(id);
@@ -1065,7 +1069,15 @@ namespace Emby.Server.Implementations.Session
var items = byName.GetTaggedItems(new InternalItemsQuery(user)
{
IsFolder = false,
- Recursive = true
+ Recursive = true,
+ DtoOptions = new DtoOptions(false)
+ {
+ EnableImages = false,
+ Fields = new List<ItemFields>
+ {
+ ItemFields.SortName
+ }
+ }
});
return FilterToSingleMediaType(items)
@@ -1077,12 +1089,20 @@ namespace Emby.Server.Implementations.Session
{
var folder = (Folder)item;
- var itemsResult = await folder.GetItems(new InternalItemsQuery(user)
+ var itemsResult = folder.GetItems(new InternalItemsQuery(user)
{
Recursive = true,
- IsFolder = false
+ IsFolder = false,
+ DtoOptions = new DtoOptions(false)
+ {
+ EnableImages = false,
+ Fields = new List<ItemFields>
+ {
+ ItemFields.SortName
+ }
+ }
- }).ConfigureAwait(false);
+ });
return FilterToSingleMediaType(itemsResult.Items)
.OrderBy(i => i.SortName)
@@ -1111,7 +1131,7 @@ namespace Emby.Server.Implementations.Session
return new List<BaseItem>();
}
- return _musicManager.GetInstantMixFromItem(item, user);
+ return _musicManager.GetInstantMixFromItem(item, user, new DtoOptions(false) { EnableImages = false });
}
public Task SendBrowseCommand(string controllingSessionId, string sessionId, BrowseRequest command, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
index 478f9da71..2735bb237 100644
--- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -57,7 +57,6 @@ namespace Emby.Server.Implementations.Session
_json = json;
_httpServer = httpServer;
_serverManager = serverManager;
- httpServer.WebSocketConnecting += _httpServer_WebSocketConnecting;
serverManager.WebSocketConnected += _serverManager_WebSocketConnected;
}
@@ -84,27 +83,6 @@ namespace Emby.Server.Implementations.Session
}
}
- async void _httpServer_WebSocketConnecting(object sender, WebSocketConnectingEventArgs e)
- {
- //var token = e.QueryString["api_key"];
- //if (!string.IsNullOrWhiteSpace(token))
- //{
- // try
- // {
- // var session = await GetSession(e.QueryString, e.Endpoint).ConfigureAwait(false);
-
- // if (session == null)
- // {
- // e.AllowConnection = false;
- // }
- // }
- // catch (Exception ex)
- // {
- // _logger.ErrorException("Error getting session info", ex);
- // }
- //}
- }
-
private Task<SessionInfo> GetSession(QueryParamCollection queryString, string remoteEndpoint)
{
if (queryString == null)
@@ -123,7 +101,6 @@ namespace Emby.Server.Implementations.Session
public void Dispose()
{
- _httpServer.WebSocketConnecting -= _httpServer_WebSocketConnecting;
_serverManager.WebSocketConnected -= _serverManager_WebSocketConnected;
}
diff --git a/Emby.Server.Implementations/TV/SeriesPostScanTask.cs b/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
index 3d93561f1..23b6a3cb5 100644
--- a/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
+++ b/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
@@ -58,7 +59,8 @@ namespace Emby.Server.Implementations.TV
{
IncludeItemTypes = new[] { typeof(Series).Name },
Recursive = true,
- GroupByPresentationUniqueKey = false
+ GroupByPresentationUniqueKey = false,
+ DtoOptions = new DtoOptions(true)
}).Cast<Series>().ToList();
@@ -188,7 +190,8 @@ namespace Emby.Server.Implementations.TV
{
IncludeItemTypes = new[] { typeof(Series).Name },
Recursive = true,
- GroupByPresentationUniqueKey = false
+ GroupByPresentationUniqueKey = false,
+ DtoOptions = new DtoOptions(true)
}).Cast<Series>().ToList();
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index b5e64bc23..876c5d58b 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
namespace Emby.Server.Implementations.TV
{
@@ -26,7 +27,7 @@ namespace Emby.Server.Implementations.TV
_config = config;
}
- public QueryResult<BaseItem> GetNextUp(NextUpQuery request)
+ public QueryResult<BaseItem> GetNextUp(NextUpQuery request, DtoOptions dtoOptions)
{
var user = _userManager.GetUserById(request.UserId);
@@ -68,19 +69,19 @@ namespace Emby.Server.Implementations.TV
{
Fields = new List<ItemFields>
{
-
+ ItemFields.PresentationUniqueKey
}
}
}).Cast<Series>().Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
- var episodes = GetNextUpEpisodes(request, user, items);
+ var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
return GetResult(episodes, request);
}
- public QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<Folder> parentsFolders)
+ public QueryResult<BaseItem> GetNextUp(NextUpQuery request, List<Folder> parentsFolders, DtoOptions dtoOptions)
{
var user = _userManager.GetUserById(request.UserId);
@@ -118,7 +119,7 @@ namespace Emby.Server.Implementations.TV
{
Fields = new List<ItemFields>
{
-
+ ItemFields.PresentationUniqueKey
},
EnableImages = false
}
@@ -126,18 +127,18 @@ namespace Emby.Server.Implementations.TV
}, parentsFolders.Cast<BaseItem>().ToList()).Cast<Series>().Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
- var episodes = GetNextUpEpisodes(request, user, items);
+ var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
return GetResult(episodes, request);
}
- public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable<string> seriesKeys)
+ public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable<string> seriesKeys, DtoOptions dtoOptions)
{
// Avoid implicitly captured closure
var currentUser = user;
var allNextUp = seriesKeys
- .Select(i => GetNextUp(i, currentUser));
+ .Select(i => GetNextUp(i, currentUser, dtoOptions));
//allNextUp = allNextUp.OrderByDescending(i => i.Item1);
@@ -175,14 +176,12 @@ namespace Emby.Server.Implementations.TV
/// Gets the next up.
/// </summary>
/// <returns>Task{Episode}.</returns>
- private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user)
+ private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions)
{
- var enableSeriesPresentationKey = _config.Configuration.EnableSeriesPresentationUniqueKey;
-
var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- AncestorWithPresentationUniqueKey = enableSeriesPresentationKey ? null : seriesKey,
- SeriesPresentationUniqueKey = enableSeriesPresentationKey ? seriesKey : null,
+ AncestorWithPresentationUniqueKey = null,
+ SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { ItemSortBy.SortName },
SortOrder = SortOrder.Descending,
@@ -193,7 +192,7 @@ namespace Emby.Server.Implementations.TV
{
Fields = new List<ItemFields>
{
-
+ ItemFields.SortName
},
EnableImages = false
}
@@ -204,8 +203,8 @@ namespace Emby.Server.Implementations.TV
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- AncestorWithPresentationUniqueKey = enableSeriesPresentationKey ? null : seriesKey,
- SeriesPresentationUniqueKey = enableSeriesPresentationKey ? seriesKey : null,
+ AncestorWithPresentationUniqueKey = null,
+ SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name },
SortBy = new[] { ItemSortBy.SortName },
SortOrder = SortOrder.Ascending,
@@ -213,7 +212,8 @@ namespace Emby.Server.Implementations.TV
IsPlayed = false,
IsVirtualItem = false,
ParentIndexNumberNotEquals = 0,
- MinSortName = lastWatchedEpisode == null ? null : lastWatchedEpisode.SortName
+ MinSortName = lastWatchedEpisode == null ? null : lastWatchedEpisode.SortName,
+ DtoOptions = dtoOptions
}).Cast<Episode>().FirstOrDefault();
};
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index 21ef3cab6..8dc1fae4b 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -139,30 +139,58 @@ namespace Emby.Server.Implementations.Udp
{
_udpClient = _socketFactory.CreateUdpSocket(port);
- Task.Run(() => StartListening());
+ Task.Run(() => BeginReceive());
}
- private async void StartListening()
+ private readonly byte[] _receiveBuffer = new byte[8192];
+
+ private void BeginReceive()
{
- while (!_isDisposed)
+ if (_isDisposed)
{
- try
- {
- var result = await _udpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
- OnMessageReceived(result);
- }
- catch (ObjectDisposedException)
- {
- }
- catch (OperationCanceledException)
- {
- }
- catch (Exception ex)
+ try
+ {
+ var result = _udpClient.BeginReceive(_receiveBuffer, 0, _receiveBuffer.Length, OnReceiveResult);
+
+ if (result.CompletedSynchronously)
{
- _logger.ErrorException("Error receiving udp message", ex);
+ OnReceiveResult(result);
}
}
+ catch (ObjectDisposedException)
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error receiving udp message", ex);
+ }
+ }
+
+ private void OnReceiveResult(IAsyncResult result)
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ try
+ {
+ var socketResult = _udpClient.EndReceive(result);
+
+ OnMessageReceived(socketResult);
+ }
+ catch (ObjectDisposedException)
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error receiving udp message", ex);
+ }
+
+ BeginReceive();
}
/// <summary>
@@ -239,13 +267,13 @@ namespace Emby.Server.Implementations.Udp
try
{
- await _udpClient.SendWithLockAsync(bytes, bytes.Length, remoteEndPoint, CancellationToken.None).ConfigureAwait(false);
+ await _udpClient.SendToAsync(bytes, 0, bytes.Length, remoteEndPoint, CancellationToken.None).ConfigureAwait(false);
_logger.Info("Udp message sent to {0}", remoteEndPoint);
}
catch (OperationCanceledException)
{
-
+
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
index ab6307238..f54613384 100644
--- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
@@ -11,9 +11,9 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Emby.Server.Implementations.Images;
-using MediaBrowser.Common.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
@@ -36,19 +36,20 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override async Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var view = (CollectionFolder)item;
var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
- var result = await view.GetItems(new InternalItemsQuery
+ var result = view.GetItems(new InternalItemsQuery
{
CollapseBoxSetItems = false,
Recursive = recursive,
- ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" }
+ ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" },
+ DtoOptions = new DtoOptions(false)
- }).ConfigureAwait(false);
+ });
var items = result.Items.Select(i =>
{
@@ -98,7 +99,7 @@ namespace Emby.Server.Implementations.UserViews
return item is CollectionFolder;
}
- protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
@@ -109,10 +110,10 @@ namespace Emby.Server.Implementations.UserViews
return null;
}
- return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false);
+ return CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540);
}
- return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false);
+ return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex);
}
}
@@ -133,7 +134,7 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override async Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var view = (ManualCollectionsFolder)item;
@@ -144,7 +145,8 @@ namespace Emby.Server.Implementations.UserViews
Recursive = recursive,
IncludeItemTypes = new[] { typeof(BoxSet).Name },
Limit = 20,
- SortBy = new[] { ItemSortBy.Random }
+ SortBy = new[] { ItemSortBy.Random },
+ DtoOptions = new DtoOptions(false)
});
return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
@@ -155,7 +157,7 @@ namespace Emby.Server.Implementations.UserViews
return item is ManualCollectionsFolder;
}
- protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
@@ -166,10 +168,10 @@ namespace Emby.Server.Implementations.UserViews
return null;
}
- return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false);
+ return CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540);
}
- return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false);
+ return base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex);
}
}
diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
index b8d03db3d..cd2c4728f 100644
--- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Emby.Server.Implementations.Images;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Extensions;
@@ -47,7 +48,7 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override async Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasImages item)
{
var view = (UserView)item;
@@ -58,7 +59,9 @@ namespace Emby.Server.Implementations.UserViews
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
ImageTypes = new[] { ImageType.Primary },
Limit = 30,
- IsMovie = true
+ IsMovie = true,
+ DtoOptions = new DtoOptions(false)
+
}).ToList();
return GetFinalItems(programs).ToList();
@@ -67,9 +70,10 @@ namespace Emby.Server.Implementations.UserViews
if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
{
- var userItemsResult = await view.GetItems(new InternalItemsQuery
+ var userItemsResult = view.GetItems(new InternalItemsQuery
{
- CollapseBoxSetItems = false
+ CollapseBoxSetItems = false,
+ DtoOptions = new DtoOptions(false)
});
return userItemsResult.Items.ToList();
@@ -78,14 +82,14 @@ namespace Emby.Server.Implementations.UserViews
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
- var result = await view.GetItems(new InternalItemsQuery
+ var result = view.GetItems(new InternalItemsQuery
{
User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null,
CollapseBoxSetItems = false,
Recursive = recursive,
ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Person" },
-
- }).ConfigureAwait(false);
+ DtoOptions = new DtoOptions(false)
+ });
var items = result.Items.Select(i =>
{
@@ -159,7 +163,7 @@ namespace Emby.Server.Implementations.UserViews
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
}
- protected override async Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
if (itemsWithImages.Count == 0)
{
@@ -168,7 +172,7 @@ namespace Emby.Server.Implementations.UserViews
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
- return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false);
+ return CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540);
}
}
}