commit
dc578f3742
|
@ -32,8 +32,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\NLog.4.4.12\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
|
||||
|
|
|
@ -152,13 +152,23 @@ namespace Emby.Common.Implementations.Logging
|
|||
|
||||
RemoveTarget("ApplicationLogFileWrapper");
|
||||
|
||||
var wrapper = new AsyncTargetWrapper();
|
||||
// https://github.com/NLog/NLog/wiki/Performance
|
||||
var wrapper = new AsyncTargetWrapper
|
||||
{
|
||||
OverflowAction = AsyncTargetWrapperOverflowAction.Block,
|
||||
QueueLimit = 10000,
|
||||
BatchSize = 500,
|
||||
TimeToSleepBetweenBatches = 50
|
||||
};
|
||||
|
||||
wrapper.Name = "ApplicationLogFileWrapper";
|
||||
|
||||
var logFile = new FileTarget
|
||||
{
|
||||
FileName = path,
|
||||
Layout = "${longdate} ${level} ${logger}: ${message}"
|
||||
Layout = "${longdate} ${level} ${logger}: ${message}",
|
||||
KeepFileOpen = true,
|
||||
ConcurrentWrites = false
|
||||
};
|
||||
|
||||
logFile.Name = "ApplicationLogFile";
|
||||
|
|
|
@ -37,8 +37,6 @@ namespace Emby.Common.Implementations.Net
|
|||
private TaskCompletionSource<SocketReceiveResult> _currentReceiveTaskCompletionSource;
|
||||
private TaskCompletionSource<int> _currentSendTaskCompletionSource;
|
||||
|
||||
private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
|
||||
|
||||
public UdpSocket(Socket socket, int localPort, IPAddress ip)
|
||||
{
|
||||
if (socket == null) throw new ArgumentNullException("socket");
|
||||
|
@ -234,8 +232,6 @@ namespace Emby.Common.Implementations.Net
|
|||
if (socket != null)
|
||||
socket.Dispose();
|
||||
|
||||
_sendLock.Dispose();
|
||||
|
||||
var tcs = _currentReceiveTaskCompletionSource;
|
||||
if (tcs != null)
|
||||
{
|
||||
|
|
|
@ -506,7 +506,7 @@ namespace Emby.Common.Implementations.Networking
|
|||
public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
|
||||
{
|
||||
var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
|
||||
return addresses.Select(ToIpAddressInfo).ToArray();
|
||||
return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -14,6 +14,7 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Common.Implementations.ScheduledTasks
|
||||
{
|
||||
|
@ -274,7 +275,8 @@ namespace Emby.Common.Implementations.ScheduledTasks
|
|||
{
|
||||
get
|
||||
{
|
||||
return InternalTriggers.Select(i => i.Item1).ToArray();
|
||||
var triggers = InternalTriggers;
|
||||
return triggers.Select(i => i.Item1).ToArray(triggers.Length);
|
||||
}
|
||||
set
|
||||
{
|
||||
|
@ -288,7 +290,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
|
|||
|
||||
SaveTriggers(triggerList);
|
||||
|
||||
InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
|
||||
InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray(triggerList.Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="4.4.11" targetFramework="net46" />
|
||||
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
|
||||
<package id="NLog" version="4.4.12" targetFramework="net46" />
|
||||
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
|
||||
<package id="SharpCompress" version="0.14.0" targetFramework="net462" />
|
||||
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
|
||||
</packages>
|
|
@ -12,6 +12,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
|
@ -31,6 +32,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly Func<IMediaEncoder> _mediaEncoder;
|
||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
|
||||
public ContentDirectory(IDlnaManager dlna,
|
||||
IUserDataManager userDataManager,
|
||||
|
@ -39,7 +41,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
IServerConfigurationManager config,
|
||||
IUserManager userManager,
|
||||
ILogger logger,
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
|
||||
: base(logger, httpClient)
|
||||
{
|
||||
_dlna = dlna;
|
||||
|
@ -54,6 +56,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
_userViewManager = userViewManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
||||
_tvSeriesManager = tvSeriesManager;
|
||||
}
|
||||
|
||||
private int SystemUpdateId
|
||||
|
@ -97,7 +100,8 @@ namespace Emby.Dlna.ContentDirectory
|
|||
_mediaSourceManager,
|
||||
_userViewManager,
|
||||
_mediaEncoder(),
|
||||
XmlReaderSettingsFactory)
|
||||
XmlReaderSettingsFactory,
|
||||
_tvSeriesManager)
|
||||
.ProcessControlRequest(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@ using MediaBrowser.Controller.Dto;
|
|||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Xml;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
|
@ -40,6 +42,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
private readonly IServerConfigurationManager _config;
|
||||
private readonly User _user;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
|
||||
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
|
||||
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
|
||||
|
@ -53,7 +56,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private readonly DeviceProfile _profile;
|
||||
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
|
||||
: base(config, logger, xmlReaderSettingsFactory)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -62,6 +65,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
_systemUpdateId = systemUpdateId;
|
||||
_channelManager = channelManager;
|
||||
_userViewManager = userViewManager;
|
||||
_tvSeriesManager = tvSeriesManager;
|
||||
_profile = profile;
|
||||
_config = config;
|
||||
|
||||
|
@ -454,14 +458,14 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
SortBy = sortOrders.ToArray(),
|
||||
SortBy = sortOrders.ToArray(sortOrders.Count),
|
||||
SortOrder = sort.SortOrder,
|
||||
User = user,
|
||||
Recursive = true,
|
||||
IsMissing = false,
|
||||
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
|
||||
IsFolder = isFolder,
|
||||
MediaTypes = mediaTypes.ToArray(),
|
||||
MediaTypes = mediaTypes.ToArray(mediaTypes.Count),
|
||||
DtoOptions = GetDtoOptions()
|
||||
});
|
||||
}
|
||||
|
@ -488,6 +492,14 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
|
||||
}
|
||||
if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
|
||||
}
|
||||
if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetTvFolders(item, user, stubType, sort, startIndex, limit);
|
||||
}
|
||||
|
||||
if (stubType.HasValue)
|
||||
{
|
||||
|
@ -497,12 +509,12 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
ItemId = item.Id
|
||||
|
||||
}).ToArray();
|
||||
});
|
||||
|
||||
var result = new QueryResult<ServerItem>
|
||||
{
|
||||
Items = items.Select(i => new ServerItem(i)).ToArray(),
|
||||
TotalRecordCount = items.Length
|
||||
Items = items.Select(i => new ServerItem(i)).ToArray(items.Count),
|
||||
TotalRecordCount = items.Count
|
||||
};
|
||||
|
||||
return ApplyPaging(result, startIndex, limit);
|
||||
|
@ -524,8 +536,8 @@ namespace Emby.Dlna.ContentDirectory
|
|||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
User = user,
|
||||
IsMissing = false,
|
||||
PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows },
|
||||
IsVirtualItem = false,
|
||||
PresetViews = new string[] { },
|
||||
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
|
||||
IsPlaceHolder = false,
|
||||
DtoOptions = GetDtoOptions()
|
||||
|
@ -651,11 +663,236 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(),
|
||||
Items = list.ToArray(list.Count),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
|
||||
{
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
StartIndex = startIndex,
|
||||
Limit = limit
|
||||
};
|
||||
SetSorting(query, sort, false);
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
|
||||
{
|
||||
return GetMovieContinueWatching(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Latest)
|
||||
{
|
||||
return GetMovieLatest(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Movies)
|
||||
{
|
||||
return GetMovieMovies(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Collections)
|
||||
{
|
||||
return GetMovieCollections(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Favorites)
|
||||
{
|
||||
return GetMovieFavorites(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Genres)
|
||||
{
|
||||
return GetGenres(item, user, query);
|
||||
}
|
||||
|
||||
var list = new List<ServerItem>();
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.ContinueWatching
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Latest
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Movies
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Collections
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Favorites
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Genres
|
||||
});
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
|
||||
{
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
StartIndex = startIndex,
|
||||
Limit = limit
|
||||
};
|
||||
SetSorting(query, sort, false);
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
|
||||
{
|
||||
return GetMovieContinueWatching(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.NextUp)
|
||||
{
|
||||
return GetNextUp(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Latest)
|
||||
{
|
||||
return GetTvLatest(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Series)
|
||||
{
|
||||
return GetSeries(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.FavoriteSeries)
|
||||
{
|
||||
return GetFavoriteSeries(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.FavoriteEpisodes)
|
||||
{
|
||||
return GetFavoriteEpisodes(item, user, query);
|
||||
}
|
||||
|
||||
if (stubType.HasValue && stubType.Value == StubType.Genres)
|
||||
{
|
||||
return GetGenres(item, user, query);
|
||||
}
|
||||
|
||||
var list = new List<ServerItem>();
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.ContinueWatching
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.NextUp
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Latest
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Series
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.FavoriteSeries
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.FavoriteEpisodes
|
||||
});
|
||||
|
||||
list.Add(new ServerItem(item)
|
||||
{
|
||||
StubType = StubType.Genres
|
||||
});
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
Items = list.ToArray(list.Count),
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.OrderBy = new List<Tuple<string, SortOrder>>
|
||||
{
|
||||
new Tuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
|
||||
new Tuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
|
||||
};
|
||||
|
||||
query.IsResumable = true;
|
||||
query.Limit = 10;
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetSeries(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { typeof(Series).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { typeof(Movie).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieCollections(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
//query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
|
@ -695,6 +932,45 @@ namespace Emby.Dlna.ContentDirectory
|
|||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { typeof(Series).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { typeof(Episode).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { typeof(Movie).Name };
|
||||
|
||||
var result = _libraryManager.GetItemsResult(query);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
|
@ -708,6 +984,24 @@ namespace Emby.Dlna.ContentDirectory
|
|||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetGenres(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user)
|
||||
{
|
||||
AncestorIds = new[] { parent.Id.ToString("N") },
|
||||
StartIndex = query.StartIndex,
|
||||
Limit = query.Limit
|
||||
});
|
||||
|
||||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = genresResult.TotalRecordCount,
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user)
|
||||
|
@ -720,7 +1014,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = genresResult.TotalRecordCount,
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray()
|
||||
Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -738,7 +1032,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -756,7 +1050,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -775,7 +1069,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var result = new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = artists.TotalRecordCount,
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray()
|
||||
Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
|
||||
};
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -810,6 +1104,55 @@ namespace Emby.Dlna.ContentDirectory
|
|||
return ToResult(items);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SortBy = new string[] { };
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||
{
|
||||
Limit = query.Limit,
|
||||
StartIndex = query.StartIndex,
|
||||
UserId = query.User.Id.ToString("N")
|
||||
|
||||
}, new List<Folder> { (Folder)parent }, query.DtoOptions);
|
||||
|
||||
return ToResult(result);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SortBy = new string[] { };
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
UserId = user.Id.ToString("N"),
|
||||
Limit = 50,
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
ParentId = parent == null ? null : parent.Id.ToString("N"),
|
||||
GroupItems = false
|
||||
|
||||
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
|
||||
|
||||
return ToResult(items);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SortBy = new string[] { };
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
UserId = user.Id.ToString("N"),
|
||||
Limit = 50,
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name },
|
||||
ParentId = parent == null ? null : parent.Id.ToString("N"),
|
||||
GroupItems = true
|
||||
|
||||
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
|
||||
|
||||
return ToResult(items);
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> GetMusicArtistItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
|
||||
{
|
||||
var query = new InternalItemsQuery(user)
|
||||
|
@ -854,7 +1197,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
var serverItems = result
|
||||
.Select(i => new ServerItem(i))
|
||||
.ToArray();
|
||||
.ToArray(result.Count);
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
|
@ -868,7 +1211,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
var serverItems = result
|
||||
.Items
|
||||
.Select(i => new ServerItem(i))
|
||||
.ToArray();
|
||||
.ToArray(result.Items.Length);
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
|
@ -885,7 +1228,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
sortOrders.Add(ItemSortBy.SortName);
|
||||
}
|
||||
|
||||
query.SortBy = sortOrders.ToArray();
|
||||
query.SortBy = sortOrders.ToArray(sortOrders.Count);
|
||||
query.SortOrder = sort.SortOrder;
|
||||
}
|
||||
|
||||
|
@ -901,8 +1244,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
DtoOptions = GetDtoOptions()
|
||||
});
|
||||
|
||||
var serverItems = itemsResult.Items.Select(i => new ServerItem(i))
|
||||
.ToArray();
|
||||
var serverItems = itemsResult.Items.Select(i => new ServerItem(i)).ToArray(itemsResult.Items.Length);
|
||||
|
||||
return new QueryResult<ServerItem>
|
||||
{
|
||||
|
@ -942,65 +1284,16 @@ namespace Emby.Dlna.ContentDirectory
|
|||
id = parts[23];
|
||||
}
|
||||
|
||||
if (id.StartsWith("folder_", StringComparison.OrdinalIgnoreCase))
|
||||
var enumNames = Enum.GetNames(typeof(StubType));
|
||||
foreach (var name in enumNames)
|
||||
{
|
||||
stubType = StubType.Folder;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("people_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.People;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("latest_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Latest;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("playlists_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Playlists;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("Albums_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Albums;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("AlbumArtists_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.AlbumArtists;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("Artists_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Artists;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("Genres_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Genres;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("Songs_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.Songs;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("FavoriteAlbums_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.FavoriteAlbums;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("FavoriteArtists_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.FavoriteArtists;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
}
|
||||
else if (id.StartsWith("FavoriteSongs_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = StubType.FavoriteSongs;
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
if (id.StartsWith(name + "_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stubType = (StubType)Enum.Parse(typeof(StubType), name, true);
|
||||
id = id.Split(new[] { '_' }, 2)[1];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Guid.TryParse(id, out itemId))
|
||||
|
@ -1048,6 +1341,14 @@ namespace Emby.Dlna.ContentDirectory
|
|||
Genres = 8,
|
||||
FavoriteSongs = 9,
|
||||
FavoriteArtists = 10,
|
||||
FavoriteAlbums = 11
|
||||
FavoriteAlbums = 11,
|
||||
ContinueWatching = 12,
|
||||
Movies = 13,
|
||||
Collections = 14,
|
||||
Favorites = 15,
|
||||
NextUp = 16,
|
||||
Series = 17,
|
||||
FavoriteSeries = 18,
|
||||
FavoriteEpisodes = 19
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ namespace Emby.Dlna.Didl
|
|||
{
|
||||
if (streamInfo == null)
|
||||
{
|
||||
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
|
||||
var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user);
|
||||
|
||||
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
|
||||
{
|
||||
|
@ -439,6 +439,38 @@ namespace Emby.Dlna.Didl
|
|||
{
|
||||
return _localization.GetLocalizedString("ViewTypeMusicFavoriteSongs");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeMovieResume");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeMovieMovies");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeMovieCollections");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeMovieFavorites");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeTvNextUp");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeTvFavoriteSeries");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeTvFavoriteEpisodes");
|
||||
}
|
||||
if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
|
||||
{
|
||||
return _localization.GetLocalizedString("ViewTypeTvShowSeries");
|
||||
}
|
||||
|
||||
var episode = item as Episode;
|
||||
var season = context as Season;
|
||||
|
@ -476,7 +508,7 @@ namespace Emby.Dlna.Didl
|
|||
|
||||
if (streamInfo == null)
|
||||
{
|
||||
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
|
||||
var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user);
|
||||
|
||||
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Reflection;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
|
@ -106,7 +107,6 @@ namespace Emby.Dlna
|
|||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("No matching device profile found. The default will need to be used.");
|
||||
LogUnmatchedProfile(deviceInfo);
|
||||
}
|
||||
|
||||
|
@ -220,12 +220,8 @@ namespace Emby.Dlna
|
|||
}
|
||||
else
|
||||
{
|
||||
var msg = new StringBuilder();
|
||||
foreach (var header in headers)
|
||||
{
|
||||
msg.AppendLine(header.Key + ": " + header.Value);
|
||||
}
|
||||
_logger.LogMultiline("No matching device profile found. The default will need to be used.", LogSeverity.Info, msg);
|
||||
var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(headers.Count));
|
||||
_logger.Debug("No matching device profile found. {0}", headerString);
|
||||
}
|
||||
|
||||
return profile;
|
||||
|
|
|
@ -15,6 +15,7 @@ using System.Threading.Tasks;
|
|||
using System.Xml.Linq;
|
||||
using Emby.Dlna.Server;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
|
@ -112,7 +113,7 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
private int GetInactiveTimerIntervalMs()
|
||||
{
|
||||
return 30000;
|
||||
return Timeout.Infinite;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
|
@ -160,18 +161,15 @@ namespace Emby.Dlna.PlayTo
|
|||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (!_timerActive)
|
||||
lock (_timerLock)
|
||||
{
|
||||
lock (_timerLock)
|
||||
if (!_timerActive)
|
||||
{
|
||||
if (!_timerActive)
|
||||
{
|
||||
_logger.Debug("RestartTimer");
|
||||
_timer.Change(10, GetPlaybackTimerIntervalMs());
|
||||
}
|
||||
|
||||
_timerActive = true;
|
||||
_logger.Debug("RestartTimer");
|
||||
_timer.Change(10, GetPlaybackTimerIntervalMs());
|
||||
}
|
||||
|
||||
_timerActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,23 +181,20 @@ namespace Emby.Dlna.PlayTo
|
|||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (_timerActive)
|
||||
lock (_timerLock)
|
||||
{
|
||||
lock (_timerLock)
|
||||
if (_timerActive)
|
||||
{
|
||||
if (_timerActive)
|
||||
_logger.Debug("RestartTimerInactive");
|
||||
var interval = GetInactiveTimerIntervalMs();
|
||||
|
||||
if (_timer != null)
|
||||
{
|
||||
_logger.Debug("RestartTimerInactive");
|
||||
var interval = GetInactiveTimerIntervalMs();
|
||||
|
||||
if (_timer != null)
|
||||
{
|
||||
_timer.Change(interval, interval);
|
||||
}
|
||||
_timer.Change(interval, interval);
|
||||
}
|
||||
|
||||
_timerActive = false;
|
||||
}
|
||||
|
||||
_timerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,6 +487,10 @@ namespace Emby.Dlna.PlayTo
|
|||
RestartTimer();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RestartTimerInactive();
|
||||
}
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
|
@ -890,7 +889,7 @@ namespace Emby.Dlna.PlayTo
|
|||
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
|
||||
friendlyNames.Add(room.Value);
|
||||
|
||||
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
|
||||
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray(friendlyNames.Count));
|
||||
|
||||
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
|
||||
if (model != null)
|
||||
|
|
|
@ -503,7 +503,7 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
var hasMediaSources = item as IHasMediaSources;
|
||||
var mediaSources = hasMediaSources != null
|
||||
? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
|
||||
? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user))
|
||||
: new List<MediaSourceInfo>();
|
||||
|
||||
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Model.Dlna;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Dlna.Profiles
|
||||
{
|
||||
|
@ -172,7 +173,7 @@ namespace Emby.Dlna.Profiles
|
|||
Value = value
|
||||
});
|
||||
|
||||
XmlRootAttributes = list.ToArray();
|
||||
XmlRootAttributes = list.ToArray(list.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ namespace Emby.Dlna.Server
|
|||
}
|
||||
}
|
||||
|
||||
var characters = characterList.ToArray();
|
||||
var characters = characterList.ToArray(characterList.Count);
|
||||
|
||||
var serverName = new string(characters);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Xml;
|
|||
using Emby.Dlna.Didl;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using MediaBrowser.Model.Xml;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Dlna.Service
|
||||
{
|
||||
|
@ -235,26 +236,29 @@ namespace Emby.Dlna.Service
|
|||
|
||||
private void LogRequest(ControlRequest request)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
if (!Config.GetDlnaConfiguration().EnableDebugLog)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
||||
builder.AppendFormat("Headers: {0}", headers);
|
||||
builder.AppendLine();
|
||||
//builder.Append(request.InputXml);
|
||||
var originalHeaders = request.Headers;
|
||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
|
||||
|
||||
Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
|
||||
Logger.Debug("Control request. Headers: {0}", headers);
|
||||
}
|
||||
|
||||
private void LogResponse(ControlResponse response)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
if (!Config.GetDlnaConfiguration().EnableDebugLog)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var headers = string.Join(", ", response.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
||||
builder.AppendFormat("Headers: {0}", headers);
|
||||
builder.AppendLine();
|
||||
builder.Append(response.Xml);
|
||||
var originalHeaders = response.Headers;
|
||||
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
|
||||
//builder.Append(response.Xml);
|
||||
|
||||
Logger.LogMultiline("Control response", LogSeverity.Debug, builder);
|
||||
Logger.Debug("Control response. Headers: {0}", headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,10 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Emby.Drawing.Common;
|
||||
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using TagLib;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Drawing
|
||||
{
|
||||
|
@ -171,6 +169,13 @@ namespace Emby.Drawing
|
|||
return _imageEncoder.SupportedOutputFormats;
|
||||
}
|
||||
|
||||
private static readonly string[] TransparentImageTypes = new string[] { ".png", ".webp" };
|
||||
private bool SupportsTransparency(string path)
|
||||
{
|
||||
return TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
|
||||
;
|
||||
}
|
||||
|
||||
public async Task<Tuple<string, string, DateTime>> ProcessImage(ImageProcessingOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
|
@ -179,7 +184,7 @@ namespace Emby.Drawing
|
|||
}
|
||||
|
||||
var originalImage = options.Image;
|
||||
IHasImages item = options.Item;
|
||||
IHasMetadata item = options.Item;
|
||||
|
||||
if (!originalImage.IsLocalFile)
|
||||
{
|
||||
|
@ -260,6 +265,11 @@ namespace Emby.Drawing
|
|||
item = _libraryManager().GetItemById(options.ItemId);
|
||||
}
|
||||
|
||||
if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath))
|
||||
{
|
||||
options.CropWhiteSpace = false;
|
||||
}
|
||||
|
||||
var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat);
|
||||
|
||||
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -594,7 +604,7 @@ namespace Emby.Drawing
|
|||
/// <param name="image">The image.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public string GetImageCacheTag(IHasImages item, ItemImageInfo image)
|
||||
public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
|
@ -619,7 +629,7 @@ namespace Emby.Drawing
|
|||
/// <param name="imageEnhancers">The image enhancers.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public string GetImageCacheTag(IHasImages item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
|
||||
public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
|
@ -650,7 +660,7 @@ namespace Emby.Drawing
|
|||
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
|
||||
cacheKeys.Add(originalImagePath + dateModified.Ticks);
|
||||
|
||||
return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
|
||||
return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -660,7 +670,7 @@ namespace Emby.Drawing
|
|||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>Task{System.String}.</returns>
|
||||
public async Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex)
|
||||
public async Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex)
|
||||
{
|
||||
var enhancers = GetSupportedEnhancers(item, imageType).ToList();
|
||||
|
||||
|
@ -672,7 +682,7 @@ namespace Emby.Drawing
|
|||
}
|
||||
|
||||
private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
|
||||
IHasImages item,
|
||||
IHasMetadata item,
|
||||
int imageIndex,
|
||||
List<IImageEnhancer> enhancers)
|
||||
{
|
||||
|
@ -717,7 +727,7 @@ namespace Emby.Drawing
|
|||
/// item
|
||||
/// </exception>
|
||||
private async Task<string> GetEnhancedImageInternal(string originalImagePath,
|
||||
IHasImages item,
|
||||
IHasMetadata item,
|
||||
ImageType imageType,
|
||||
int imageIndex,
|
||||
IEnumerable<IImageEnhancer> supportedEnhancers,
|
||||
|
@ -771,7 +781,7 @@ namespace Emby.Drawing
|
|||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>Task{EnhancedImage}.</returns>
|
||||
private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasImages item, ImageType imageType, int imageIndex)
|
||||
private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasMetadata item, ImageType imageType, int imageIndex)
|
||||
{
|
||||
// Run the enhancers sequentially in order of priority
|
||||
foreach (var enhancer in imageEnhancers)
|
||||
|
@ -856,7 +866,7 @@ namespace Emby.Drawing
|
|||
_logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
|
||||
}
|
||||
|
||||
public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType)
|
||||
public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType)
|
||||
{
|
||||
return ImageEnhancers.Where(i =>
|
||||
{
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace Emby.Photos
|
|||
}
|
||||
|
||||
item.Genres = image.ImageTag.Genres.ToList();
|
||||
item.Tags = image.ImageTag.Keywords.ToList();
|
||||
item.Tags = image.ImageTag.Keywords;
|
||||
item.Software = image.ImageTag.Software;
|
||||
|
||||
if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Emby.Server.Core</RootNamespace>
|
||||
<AssemblyName>Emby.Server.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<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>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
<Link>Properties\SharedVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="ApplicationHost.cs" />
|
||||
<Compile Include="ApplicationPathHelper.cs" />
|
||||
<Compile Include="Cryptography\ASN1.cs" />
|
||||
<Compile Include="Cryptography\ASN1Convert.cs" />
|
||||
<Compile Include="Cryptography\BitConverterLE.cs" />
|
||||
<Compile Include="Cryptography\CertificateGenerator.cs" />
|
||||
<Compile Include="Cryptography\CryptoConvert.cs" />
|
||||
<Compile Include="Cryptography\PfxGenerator.cs" />
|
||||
<Compile Include="Cryptography\PKCS1.cs" />
|
||||
<Compile Include="Cryptography\PKCS12.cs" />
|
||||
<Compile Include="Cryptography\PKCS7.cs" />
|
||||
<Compile Include="Cryptography\PKCS8.cs" />
|
||||
<Compile Include="Cryptography\X501Name.cs" />
|
||||
<Compile Include="Cryptography\X509Builder.cs" />
|
||||
<Compile Include="Cryptography\X509Certificate.cs" />
|
||||
<Compile Include="Cryptography\X509CertificateBuilder.cs" />
|
||||
<Compile Include="Cryptography\X509CertificateCollection.cs" />
|
||||
<Compile Include="Cryptography\X509Extension.cs" />
|
||||
<Compile Include="Cryptography\X509Extensions.cs" />
|
||||
<Compile Include="Cryptography\X520Attributes.cs" />
|
||||
<Compile Include="EntryPoints\ExternalPortForwarding.cs" />
|
||||
<Compile Include="HttpServerFactory.cs" />
|
||||
<Compile Include="IO\LibraryMonitor.cs" />
|
||||
<Compile Include="IO\MemoryStreamProvider.cs" />
|
||||
<Compile Include="Localization\TextLocalizer.cs" />
|
||||
<Compile Include="Logging\ConsoleLogger.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SystemEvents.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
|
||||
<Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
|
||||
<Name>Emby.Common.Implementations</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
|
||||
<Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
|
||||
<Name>Emby.Dlna</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
|
||||
<Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
|
||||
<Name>Emby.Drawing</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
|
||||
<Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
|
||||
<Name>Emby.Photos</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
|
||||
<Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
|
||||
<Name>Emby.Server.Implementations</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
|
||||
<Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
|
||||
<Name>MediaBrowser.Api</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
|
||||
<Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
|
||||
<Name>MediaBrowser.LocalMetadata</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
|
||||
<Project>{0bd82fa6-eb8a-4452-8af5-74f9c3849451}</Project>
|
||||
<Name>MediaBrowser.MediaEncoding</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
|
||||
<Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
|
||||
<Name>MediaBrowser.Providers</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
|
||||
<Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
|
||||
<Name>MediaBrowser.Server.Implementations</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
|
||||
<Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
|
||||
<Name>MediaBrowser.WebDashboard</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
|
||||
<Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
|
||||
<Name>MediaBrowser.XbmcMetadata</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
|
||||
<Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
|
||||
<Name>Mono.Nat</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
|
||||
<Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
|
||||
<Name>OpenSubtitlesHandler</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
|
||||
<Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
|
||||
<Name>SocketHttpListener</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<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">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,34 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Emby.Server.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Emby.Server.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SimpleInjector" publicKeyToken="984cb50dea722e99" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.7.0" newVersion="4.0.7.0"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.2" targetFramework="net462" />
|
||||
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
|
||||
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
|
||||
</packages>
|
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Activity
|
||||
{
|
||||
|
@ -436,7 +437,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
{
|
||||
Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
||||
Type = "ScheduledTaskFailed",
|
||||
Overview = string.Join(Environment.NewLine, vals.ToArray()),
|
||||
Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)),
|
||||
ShortOverview = runningTime,
|
||||
Severity = LogSeverity.Error
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Model.Activity;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using SQLitePCL.pretty;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Activity
|
||||
{
|
||||
|
@ -94,13 +95,13 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
var whereTextWithoutPaging = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
|
||||
if (startIndex.HasValue && startIndex.Value > 0)
|
||||
{
|
||||
var pagingWhereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
|
||||
whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
|
||||
pagingWhereText,
|
||||
|
@ -109,7 +110,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
var whereText = whereClauses.Count == 0 ?
|
||||
string.Empty :
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
||||
" where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
|
||||
|
||||
commandText += whereText;
|
||||
|
||||
|
@ -154,7 +155,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
|
||||
}
|
||||
|
||||
result.Items = list.ToArray();
|
||||
result.Items = list.ToArray(list.Count);
|
||||
return result;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
|
|
|
@ -1,11 +1,52 @@
|
|||
using MediaBrowser.Api;
|
||||
using Emby.Common.Implementations;
|
||||
using Emby.Common.Implementations.Archiving;
|
||||
using Emby.Common.Implementations.IO;
|
||||
using Emby.Common.Implementations.Reflection;
|
||||
using Emby.Common.Implementations.ScheduledTasks;
|
||||
using Emby.Common.Implementations.Serialization;
|
||||
using Emby.Common.Implementations.TextEncoding;
|
||||
using Emby.Common.Implementations.Xml;
|
||||
using Emby.Dlna;
|
||||
using Emby.Dlna.ConnectionManager;
|
||||
using Emby.Dlna.ContentDirectory;
|
||||
using Emby.Dlna.Main;
|
||||
using Emby.Dlna.MediaReceiverRegistrar;
|
||||
using Emby.Dlna.Ssdp;
|
||||
using Emby.Drawing;
|
||||
using Emby.Photos;
|
||||
using Emby.Server.Implementations.Activity;
|
||||
using Emby.Server.Implementations.Channels;
|
||||
using Emby.Server.Implementations.Collections;
|
||||
using Emby.Server.Implementations.Configuration;
|
||||
using Emby.Server.Implementations.Data;
|
||||
using Emby.Server.Implementations.Devices;
|
||||
using Emby.Server.Implementations.Dto;
|
||||
using Emby.Server.Implementations.FFMpeg;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
using Emby.Server.Implementations.HttpServer.Security;
|
||||
using Emby.Server.Implementations.IO;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using Emby.Server.Implementations.LiveTv;
|
||||
using Emby.Server.Implementations.Localization;
|
||||
using Emby.Server.Implementations.MediaEncoder;
|
||||
using Emby.Server.Implementations.Migrations;
|
||||
using Emby.Server.Implementations.Notifications;
|
||||
using Emby.Server.Implementations.Playlists;
|
||||
using Emby.Server.Implementations.Security;
|
||||
using Emby.Server.Implementations.Session;
|
||||
using Emby.Server.Implementations.Social;
|
||||
using Emby.Server.Implementations.TV;
|
||||
using Emby.Server.Implementations.Updates;
|
||||
using MediaBrowser.Api;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Emby.Common.Implementations.ScheduledTasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Chapters;
|
||||
|
@ -17,7 +58,9 @@ using MediaBrowser.Controller.Dlna;
|
|||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
|
@ -35,103 +78,47 @@ using MediaBrowser.Controller.Subtitles;
|
|||
using MediaBrowser.Controller.Sync;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.LocalMetadata.Savers;
|
||||
using MediaBrowser.MediaEncoding.BdInfo;
|
||||
using MediaBrowser.MediaEncoding.Encoder;
|
||||
using MediaBrowser.MediaEncoding.Subtitles;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Updates;
|
||||
using MediaBrowser.Providers.Chapters;
|
||||
using MediaBrowser.Providers.Manager;
|
||||
using MediaBrowser.Providers.Subtitles;
|
||||
using MediaBrowser.WebDashboard.Api;
|
||||
using MediaBrowser.XbmcMetadata.Providers;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Common.Implementations;
|
||||
using Emby.Common.Implementations.Archiving;
|
||||
using Emby.Common.Implementations.IO;
|
||||
using Emby.Common.Implementations.Reflection;
|
||||
using Emby.Common.Implementations.Serialization;
|
||||
using Emby.Common.Implementations.TextEncoding;
|
||||
using Emby.Common.Implementations.Xml;
|
||||
using Emby.Photos;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Api.Playback;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using Emby.Dlna;
|
||||
using Emby.Dlna.ConnectionManager;
|
||||
using Emby.Dlna.ContentDirectory;
|
||||
using Emby.Dlna.Main;
|
||||
using Emby.Dlna.MediaReceiverRegistrar;
|
||||
using Emby.Dlna.Ssdp;
|
||||
using Emby.Server.Core;
|
||||
using Emby.Server.Implementations.Activity;
|
||||
using Emby.Server.Implementations.Devices;
|
||||
using Emby.Server.Implementations.FFMpeg;
|
||||
using Emby.Server.Core.IO;
|
||||
using Emby.Server.Core.Localization;
|
||||
using Emby.Server.Implementations.Migrations;
|
||||
using Emby.Server.Implementations.Security;
|
||||
using Emby.Server.Implementations.Social;
|
||||
using Emby.Server.Implementations.Channels;
|
||||
using Emby.Server.Implementations.Collections;
|
||||
using Emby.Server.Implementations.Dto;
|
||||
using Emby.Server.Implementations.IO;
|
||||
using Emby.Server.Implementations.FileOrganization;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
using Emby.Server.Implementations.HttpServer.Security;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using Emby.Server.Implementations.LiveTv;
|
||||
using Emby.Server.Implementations.Localization;
|
||||
using Emby.Server.Implementations.MediaEncoder;
|
||||
using Emby.Server.Implementations.Notifications;
|
||||
using Emby.Server.Implementations.Data;
|
||||
using Emby.Server.Implementations.Playlists;
|
||||
using Emby.Server.Implementations;
|
||||
using Emby.Server.Implementations.ServerManager;
|
||||
using Emby.Server.Implementations.Session;
|
||||
using Emby.Server.Implementations.TV;
|
||||
using Emby.Server.Implementations.Updates;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.News;
|
||||
using MediaBrowser.Model.Reflection;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Social;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using MediaBrowser.Model.Updates;
|
||||
using MediaBrowser.Model.Xml;
|
||||
using MediaBrowser.Providers.Chapters;
|
||||
using MediaBrowser.Providers.Manager;
|
||||
using MediaBrowser.Providers.Subtitles;
|
||||
using MediaBrowser.WebDashboard.Api;
|
||||
using MediaBrowser.XbmcMetadata.Providers;
|
||||
using OpenSubtitlesHandler;
|
||||
using ServiceStack;
|
||||
using SocketHttpListener.Primitives;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Server.MediaEncoding.Subtitles;
|
||||
using MediaBrowser.MediaEncoding.BdInfo;
|
||||
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
|
||||
using Emby.Drawing;
|
||||
using Emby.Server.Implementations.Migrations;
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
using Emby.Common.Implementations.Diagnostics;
|
||||
using Emby.Server.Implementations.Configuration;
|
||||
|
||||
namespace Emby.Server.Core
|
||||
namespace Emby.Server.Implementations
|
||||
{
|
||||
/// <summary>
|
||||
/// Class CompositionRoot
|
||||
|
@ -216,7 +203,6 @@ namespace Emby.Server.Core
|
|||
internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
|
||||
internal IItemRepository ItemRepository { get; set; }
|
||||
private INotificationsRepository NotificationsRepository { get; set; }
|
||||
private IFileOrganizationRepository FileOrganizationRepository { get; set; }
|
||||
|
||||
private INotificationManager NotificationManager { get; set; }
|
||||
private ISubtitleManager SubtitleManager { get; set; }
|
||||
|
@ -226,7 +212,6 @@ namespace Emby.Server.Core
|
|||
internal IUserViewManager UserViewManager { get; set; }
|
||||
|
||||
private IAuthenticationRepository AuthenticationRepository { get; set; }
|
||||
private ISyncRepository SyncRepository { get; set; }
|
||||
private ITVSeriesManager TVSeriesManager { get; set; }
|
||||
private ICollectionManager CollectionManager { get; set; }
|
||||
private IMediaSourceManager MediaSourceManager { get; set; }
|
||||
|
@ -360,13 +345,6 @@ namespace Emby.Server.Core
|
|||
{
|
||||
var builder = GetBaseExceptionMessage(ApplicationPaths);
|
||||
|
||||
// Skip if plugins haven't been loaded yet
|
||||
//if (Plugins != null)
|
||||
//{
|
||||
// var pluginString = string.Join("|", Plugins.Select(i => i.Name + "-" + i.Version.ToString()).ToArray());
|
||||
// builder.Insert(0, string.Format("Plugins: {0}{1}", pluginString, Environment.NewLine));
|
||||
//}
|
||||
|
||||
builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
|
||||
builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
|
||||
|
||||
|
@ -413,7 +391,7 @@ namespace Emby.Server.Core
|
|||
{
|
||||
Logger.ErrorException("Error in {0}", ex, name);
|
||||
}
|
||||
Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||
Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
|
||||
}
|
||||
Logger.Info("All entry points have started");
|
||||
|
||||
|
@ -434,41 +412,41 @@ namespace Emby.Server.Core
|
|||
|
||||
var result = new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
|
||||
|
||||
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<AudioBook>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "Keywords", "ExtraType" };
|
||||
ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<AudioBook>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds" };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -583,9 +561,6 @@ namespace Emby.Server.Core
|
|||
ItemRepository = itemRepo;
|
||||
RegisterSingleInstance(ItemRepository);
|
||||
|
||||
FileOrganizationRepository = GetFileOrganizationRepository();
|
||||
RegisterSingleInstance(FileOrganizationRepository);
|
||||
|
||||
AuthenticationRepository = GetAuthenticationRepository();
|
||||
RegisterSingleInstance(AuthenticationRepository);
|
||||
|
||||
|
@ -614,7 +589,7 @@ namespace Emby.Server.Core
|
|||
RegisterSingleInstance(HttpServer, false);
|
||||
progress.Report(10);
|
||||
|
||||
ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
|
||||
ServerManager = new ServerManager.ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
|
||||
RegisterSingleInstance(ServerManager);
|
||||
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
|
@ -644,9 +619,6 @@ namespace Emby.Server.Core
|
|||
var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
|
||||
RegisterSingleInstance<INewsService>(newsService);
|
||||
|
||||
var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager);
|
||||
RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService);
|
||||
|
||||
progress.Report(15);
|
||||
|
||||
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
|
||||
|
@ -676,7 +648,7 @@ namespace Emby.Server.Core
|
|||
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
|
||||
RegisterSingleInstance(UserViewManager);
|
||||
|
||||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory());
|
||||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager);
|
||||
RegisterSingleInstance<IContentDirectory>(contentDirectory);
|
||||
|
||||
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
|
||||
|
@ -893,7 +865,7 @@ namespace Emby.Server.Core
|
|||
probePath = info.ProbePath;
|
||||
var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
|
||||
var mediaEncoder = new MediaEncoding.Encoder.MediaEncoder(LogManager.GetLogger("MediaEncoder"),
|
||||
JsonSerializer,
|
||||
encoderPath,
|
||||
probePath,
|
||||
|
@ -932,19 +904,6 @@ namespace Emby.Server.Core
|
|||
return repo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file organization repository.
|
||||
/// </summary>
|
||||
/// <returns>Task{IUserRepository}.</returns>
|
||||
private IFileOrganizationRepository GetFileOrganizationRepository()
|
||||
{
|
||||
var repo = new SqliteFileOrganizationRepository(LogManager.GetLogger("SqliteFileOrganizationRepository"), ServerConfigurationManager.ApplicationPaths);
|
||||
|
||||
repo.Initialize();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
private IAuthenticationRepository GetAuthenticationRepository()
|
||||
{
|
||||
var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
|
||||
|
@ -1002,8 +961,6 @@ namespace Emby.Server.Core
|
|||
BaseItem.CollectionManager = CollectionManager;
|
||||
BaseItem.MediaSourceManager = MediaSourceManager;
|
||||
CollectionFolder.XmlSerializer = XmlSerializer;
|
||||
BaseStreamingService.AppHost = this;
|
||||
BaseStreamingService.HttpClient = HttpClient;
|
||||
Utilities.CryptographyProvider = CryptographyProvider;
|
||||
AuthenticatedAttribute.AuthService = AuthService;
|
||||
}
|
||||
|
@ -1276,7 +1233,7 @@ namespace Emby.Server.Core
|
|||
list.Add(GetAssembly(typeof(InstallationManager)));
|
||||
|
||||
// MediaEncoding
|
||||
list.Add(GetAssembly(typeof(MediaEncoder)));
|
||||
list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder)));
|
||||
|
||||
// Dlna
|
||||
list.Add(GetAssembly(typeof(DlnaEntryPoint)));
|
||||
|
@ -1289,10 +1246,7 @@ namespace Emby.Server.Core
|
|||
|
||||
list.AddRange(GetAssembliesWithPartsInternal());
|
||||
|
||||
// Include composable parts in the running assembly
|
||||
list.Add(GetAssembly(typeof(ApplicationHost)));
|
||||
|
||||
return list;
|
||||
return list.ToList();
|
||||
}
|
||||
|
||||
protected abstract List<Assembly> GetAssembliesWithPartsInternal();
|
||||
|
@ -1636,14 +1590,10 @@ namespace Emby.Server.Core
|
|||
/// <returns>Task{CheckForUpdateResult}.</returns>
|
||||
public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var cacheLength = TimeSpan.FromHours(3);
|
||||
var cacheLength = TimeSpan.FromHours(1);
|
||||
var updateLevel = SystemUpdateLevel;
|
||||
|
||||
if (updateLevel == PackageVersionClass.Beta)
|
||||
{
|
||||
cacheLength = TimeSpan.FromHours(1);
|
||||
}
|
||||
else if (updateLevel == PackageVersionClass.Dev)
|
||||
if (updateLevel != PackageVersionClass.Release)
|
||||
{
|
||||
cacheLength = TimeSpan.FromMinutes(5);
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
using System.Configuration;
|
||||
using System.IO;
|
||||
|
||||
namespace Emby.Server.Core
|
||||
namespace Emby.Server.Implementations
|
||||
{
|
||||
public static class ApplicationPathHelper
|
||||
{
|
|
@ -18,12 +18,12 @@ namespace Emby.Server.Implementations.Channels
|
|||
_channelManager = channelManager;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return GetChannel(item).GetSupportedChannelImages();
|
||||
}
|
||||
|
||||
public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
|
||||
public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
|
||||
{
|
||||
var channel = GetChannel(item);
|
||||
|
||||
|
@ -35,12 +35,12 @@ namespace Emby.Server.Implementations.Channels
|
|||
get { return "Channel Image Provider"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
public bool Supports(IHasMetadata item)
|
||||
{
|
||||
return item is Channel;
|
||||
}
|
||||
|
||||
private IChannel GetChannel(IHasImages item)
|
||||
private IChannel GetChannel(IHasMetadata item)
|
||||
{
|
||||
var channel = (Channel)item;
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
all = all.Take(query.Limit.Value).ToList();
|
||||
}
|
||||
|
||||
var returnItems = all.ToArray();
|
||||
var returnItems = all.ToArray(all.Count);
|
||||
|
||||
var result = new QueryResult<Channel>
|
||||
{
|
||||
|
@ -182,8 +182,10 @@ namespace Emby.Server.Implementations.Channels
|
|||
{
|
||||
};
|
||||
|
||||
var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
|
||||
.ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnItems = returnList
|
||||
.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -567,8 +569,9 @@ namespace Emby.Server.Implementations.Channels
|
|||
Fields = query.Fields.ToList()
|
||||
};
|
||||
|
||||
var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false))
|
||||
.ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false));
|
||||
var returnItems = returnList
|
||||
.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -676,12 +679,10 @@ namespace Emby.Server.Implementations.Channels
|
|||
internalItems = internalItems.Take(query.Limit.Value).ToArray();
|
||||
}
|
||||
|
||||
var returnItemArray = internalItems.ToArray();
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = totalCount,
|
||||
Items = returnItemArray
|
||||
Items = internalItems
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -813,12 +814,10 @@ namespace Emby.Server.Implementations.Channels
|
|||
|
||||
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
||||
|
||||
var returnItemArray = internalItems.ToArray();
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = totalCount,
|
||||
Items = returnItemArray
|
||||
Items = internalItems
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -837,8 +836,10 @@ namespace Emby.Server.Implementations.Channels
|
|||
Fields = query.Fields.ToList()
|
||||
};
|
||||
|
||||
var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
|
||||
.ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnItems = returnList
|
||||
.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -989,8 +990,10 @@ namespace Emby.Server.Implementations.Channels
|
|||
Fields = query.Fields.ToList()
|
||||
};
|
||||
|
||||
var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
|
||||
.ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnItems = returnList
|
||||
.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -1191,7 +1194,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
}
|
||||
}
|
||||
|
||||
var returnItemArray = all.ToArray();
|
||||
var returnItemArray = all.ToArray(all.Count);
|
||||
RefreshIfNeeded(returnItemArray);
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
|
@ -1309,7 +1312,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
{
|
||||
item.Name = info.Name;
|
||||
item.Genres = info.Genres;
|
||||
item.Studios = info.Studios;
|
||||
item.Studios = info.Studios.ToArray(info.Studios.Count);
|
||||
item.CommunityRating = info.CommunityRating;
|
||||
item.Overview = info.Overview;
|
||||
item.IndexNumber = info.IndexNumber;
|
||||
|
@ -1319,7 +1322,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
item.ProviderIds = info.ProviderIds;
|
||||
item.OfficialRating = info.OfficialRating;
|
||||
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
|
||||
item.Tags = info.Tags;
|
||||
item.Tags = info.Tags.ToArray(info.Tags.Count);
|
||||
item.HomePageUrl = info.HomePageUrl;
|
||||
}
|
||||
else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
|
||||
|
@ -1341,7 +1344,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
var hasAlbumArtists = item as IHasAlbumArtist;
|
||||
if (hasAlbumArtists != null)
|
||||
{
|
||||
hasAlbumArtists.AlbumArtists = info.AlbumArtists;
|
||||
hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray(info.AlbumArtists.Count);
|
||||
}
|
||||
|
||||
var trailer = item as Trailer;
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
{
|
||||
}
|
||||
|
||||
protected override bool Supports(IHasImages item)
|
||||
protected override bool Supports(IHasMetadata item)
|
||||
{
|
||||
// Right now this is the only way to prevent this image from getting created ahead of internet image providers
|
||||
if (!item.IsLocked)
|
||||
|
@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
return base.Supports(item);
|
||||
}
|
||||
|
||||
protected override List<BaseItem> GetItemsWithImages(IHasImages item)
|
||||
protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
|
||||
{
|
||||
var playlist = (BoxSet)item;
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
return GetFinalItems(items, 2);
|
||||
}
|
||||
|
||||
protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
|
||||
protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
|
||||
{
|
||||
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Collections
|
||||
{
|
||||
|
@ -190,7 +191,9 @@ namespace Emby.Server.Implementations.Collections
|
|||
|
||||
if (list.Count > 0)
|
||||
{
|
||||
collection.LinkedChildren.AddRange(list);
|
||||
var newList = collection.LinkedChildren.ToList();
|
||||
newList.AddRange(list);
|
||||
collection.LinkedChildren = newList.ToArray(newList.Count);
|
||||
|
||||
collection.UpdateRatingToContent();
|
||||
|
||||
|
@ -241,9 +244,9 @@ namespace Emby.Server.Implementations.Collections
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var child in list)
|
||||
if (list.Count > 0)
|
||||
{
|
||||
collection.LinkedChildren.Remove(child);
|
||||
collection.LinkedChildren = collection.LinkedChildren.Except(list).ToArray();
|
||||
}
|
||||
|
||||
collection.UpdateRatingToContent();
|
||||
|
|
|
@ -16,6 +16,7 @@ using MediaBrowser.Model.Events;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Configuration
|
||||
{
|
||||
|
@ -216,7 +217,7 @@ namespace Emby.Server.Implementations.Configuration
|
|||
|
||||
list.Add(service);
|
||||
|
||||
options.DisabledMetadataSavers = list.ToArray();
|
||||
options.DisabledMetadataSavers = list.ToArray(list.Count);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +237,7 @@ namespace Emby.Server.Implementations.Configuration
|
|||
|
||||
list.Add(options);
|
||||
|
||||
config.MetadataOptions = list.ToArray();
|
||||
config.MetadataOptions = list.ToArray(list.Count);
|
||||
}
|
||||
|
||||
return options;
|
||||
|
|
|
@ -131,25 +131,11 @@ namespace Emby.Server.Implementations.Data
|
|||
{
|
||||
queries.Add("PRAGMA temp_store = memory");
|
||||
}
|
||||
|
||||
////foreach (var query in queries)
|
||||
////{
|
||||
//// db.Execute(query);
|
||||
////}
|
||||
|
||||
//Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First());
|
||||
//Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First());
|
||||
|
||||
/*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase))
|
||||
else
|
||||
{
|
||||
queries.Add("PRAGMA journal_mode=WAL");
|
||||
|
||||
using (WriteLock.Write())
|
||||
{
|
||||
db.ExecuteAll(string.Join(";", queries.ToArray()));
|
||||
}
|
||||
queries.Add("PRAGMA temp_store = file");
|
||||
}
|
||||
else*/
|
||||
|
||||
foreach (var query in queries)
|
||||
{
|
||||
db.Execute(query);
|
||||
|
@ -208,6 +194,13 @@ namespace Emby.Server.Implementations.Data
|
|||
"pragma temp_store = memory"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
queries.AddRange(new List<string>
|
||||
{
|
||||
"pragma temp_store = file"
|
||||
});
|
||||
}
|
||||
|
||||
db.ExecuteAll(string.Join(";", queries.ToArray()));
|
||||
Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
|
||||
|
|
|
@ -11,9 +11,6 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
|
@ -34,31 +31,9 @@ namespace Emby.Server.Implementations.Data
|
|||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
public string Name
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
get { return "Clean Database"; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return "Deletes obsolete content from the database."; }
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get { return "Library"; }
|
||||
}
|
||||
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
// Ensure these objects are lazy loaded.
|
||||
// Without this there is a deadlock that will need to be investigated
|
||||
var rootChildren = _libraryManager.RootFolder.Children.ToList();
|
||||
rootChildren = _libraryManager.GetUserRootFolder().Children.ToList();
|
||||
|
||||
await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false);
|
||||
|
||||
//await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
|
||||
return CleanDeadItems(cancellationToken, progress);
|
||||
}
|
||||
|
||||
private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
|
@ -98,23 +73,5 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the triggers that define when the task will run
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[] {
|
||||
|
||||
// Every so often
|
||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
|
||||
};
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return "CleanDatabase"; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,284 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using SQLitePCL.pretty;
|
||||
|
||||
namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
public SqliteFileOrganizationRepository(ILogger logger, IServerApplicationPaths appPaths) : base(logger)
|
||||
{
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
public void Initialize()
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
RunDefaultInitialization(connection);
|
||||
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)",
|
||||
"create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)"
|
||||
};
|
||||
|
||||
connection.RunQueries(queries);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException("result");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (WriteLock.Write())
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
var commandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
|
||||
|
||||
using (var statement = db.PrepareStatement(commandText))
|
||||
{
|
||||
statement.TryBind("@ResultId", result.Id.ToGuidBlob());
|
||||
statement.TryBind("@OriginalPath", result.OriginalPath);
|
||||
|
||||
statement.TryBind("@TargetPath", result.TargetPath);
|
||||
statement.TryBind("@FileLength", result.FileSize);
|
||||
statement.TryBind("@OrganizationDate", result.Date.ToDateTimeParamValue());
|
||||
statement.TryBind("@Status", result.Status.ToString());
|
||||
statement.TryBind("@OrganizationType", result.Type.ToString());
|
||||
statement.TryBind("@StatusMessage", result.StatusMessage);
|
||||
statement.TryBind("@ExtractedName", result.ExtractedName);
|
||||
statement.TryBind("@ExtractedYear", result.ExtractedYear);
|
||||
statement.TryBind("@ExtractedSeasonNumber", result.ExtractedSeasonNumber);
|
||||
statement.TryBind("@ExtractedEpisodeNumber", result.ExtractedEpisodeNumber);
|
||||
statement.TryBind("@ExtractedEndingEpisodeNumber", result.ExtractedEndingEpisodeNumber);
|
||||
statement.TryBind("@DuplicatePaths", string.Join("|", result.DuplicatePaths.ToArray()));
|
||||
|
||||
statement.MoveNext();
|
||||
}
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
using (WriteLock.Write())
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId"))
|
||||
{
|
||||
statement.TryBind("@ResultId", id.ToGuidBlob());
|
||||
statement.MoveNext();
|
||||
}
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAll()
|
||||
{
|
||||
using (WriteLock.Write())
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
var commandText = "delete from FileOrganizerResults";
|
||||
|
||||
db.Execute(commandText);
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
throw new ArgumentNullException("query");
|
||||
}
|
||||
|
||||
using (WriteLock.Read())
|
||||
{
|
||||
using (var connection = CreateConnection(true))
|
||||
{
|
||||
var commandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
|
||||
|
||||
if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
|
||||
{
|
||||
commandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
|
||||
query.StartIndex.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
commandText += " ORDER BY OrganizationDate desc";
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
{
|
||||
commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
|
||||
}
|
||||
|
||||
var list = new List<FileOrganizationResult>();
|
||||
|
||||
using (var statement = connection.PrepareStatement(commandText))
|
||||
{
|
||||
foreach (var row in statement.ExecuteQuery())
|
||||
{
|
||||
list.Add(GetResult(row));
|
||||
}
|
||||
}
|
||||
|
||||
int count;
|
||||
using (var statement = connection.PrepareStatement("select count (ResultId) from FileOrganizerResults"))
|
||||
{
|
||||
count = statement.ExecuteQuery().SelectScalarInt().First();
|
||||
}
|
||||
|
||||
return new QueryResult<FileOrganizationResult>()
|
||||
{
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = count
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResult(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
using (WriteLock.Read())
|
||||
{
|
||||
using (var connection = CreateConnection(true))
|
||||
{
|
||||
using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId"))
|
||||
{
|
||||
statement.TryBind("@ResultId", id.ToGuidBlob());
|
||||
|
||||
foreach (var row in statement.ExecuteQuery())
|
||||
{
|
||||
return GetResult(row);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResult(IReadOnlyList<IResultSetValue> reader)
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
var result = new FileOrganizationResult
|
||||
{
|
||||
Id = reader[0].ReadGuidFromBlob().ToString("N")
|
||||
};
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.OriginalPath = reader[index].ToString();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.TargetPath = reader[index].ToString();
|
||||
}
|
||||
|
||||
index++;
|
||||
result.FileSize = reader[index].ToInt64();
|
||||
|
||||
index++;
|
||||
result.Date = reader[index].ReadDateTime();
|
||||
|
||||
index++;
|
||||
result.Status = (FileSortingStatus)Enum.Parse(typeof(FileSortingStatus), reader[index].ToString(), true);
|
||||
|
||||
index++;
|
||||
result.Type = (FileOrganizerType)Enum.Parse(typeof(FileOrganizerType), reader[index].ToString(), true);
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.StatusMessage = reader[index].ToString();
|
||||
}
|
||||
|
||||
result.OriginalFileName = Path.GetFileName(result.OriginalPath);
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.ExtractedName = reader[index].ToString();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.ExtractedYear = reader[index].ToInt();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.ExtractedSeasonNumber = reader[index].ToInt();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.ExtractedEpisodeNumber = reader[index].ToInt();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.ExtractedEndingEpisodeNumber = reader[index].ToInt();
|
||||
}
|
||||
|
||||
index++;
|
||||
if (reader[index].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
result.DuplicatePaths = reader[index].ToString().Split('|').Where(i => !string.IsNullOrEmpty(i)).ToList();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -359,11 +359,11 @@ namespace Emby.Server.Implementations.Dto
|
|||
{
|
||||
if (user == null)
|
||||
{
|
||||
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true).ToList();
|
||||
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user).ToList();
|
||||
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
}
|
||||
|
||||
if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess))
|
||||
if (/*!(item is LiveTvProgram) ||*/ fields.Contains(ItemFields.PlayAccess))
|
||||
{
|
||||
dto.PlayAccess = item.GetPlayAccess(user);
|
||||
}
|
||||
|
@ -639,7 +639,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
private void SetGameProperties(BaseItemDto dto, Game item)
|
||||
{
|
||||
dto.Players = item.PlayersSupported;
|
||||
dto.GameSystem = item.GameSystem;
|
||||
dto.MultiPartGameFiles = item.MultiPartGameFiles;
|
||||
}
|
||||
|
@ -649,12 +648,12 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.GameSystem = item.GameSystemName;
|
||||
}
|
||||
|
||||
private List<string> GetImageTags(BaseItem item, List<ItemImageInfo> images)
|
||||
private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images)
|
||||
{
|
||||
return images
|
||||
.Select(p => GetImageCacheTag(item, p))
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private string GetImageCacheTag(BaseItem item, ImageType type)
|
||||
|
@ -766,7 +765,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
}
|
||||
|
||||
dto.People = list.ToArray();
|
||||
dto.People = list.ToArray(list.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -864,11 +863,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.DateCreated = item.DateCreated;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.DisplayMediaType))
|
||||
{
|
||||
dto.DisplayMediaType = item.DisplayMediaType;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.Settings))
|
||||
{
|
||||
dto.LockedFields = item.LockedFields;
|
||||
|
@ -894,11 +888,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.Tags = item.Tags;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.Keywords))
|
||||
{
|
||||
dto.Keywords = item.Keywords;
|
||||
}
|
||||
|
||||
var hasAspectRatio = item as IHasAspectRatio;
|
||||
if (hasAspectRatio != null)
|
||||
{
|
||||
|
@ -1003,7 +992,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
{
|
||||
dto.RemoteTrailers = hasTrailers != null ?
|
||||
hasTrailers.RemoteTrailers :
|
||||
new List<MediaUrl>();
|
||||
new MediaUrl[] {};
|
||||
}
|
||||
|
||||
dto.Name = item.Name;
|
||||
|
@ -1059,12 +1048,12 @@ namespace Emby.Server.Implementations.Dto
|
|||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.Tagline))
|
||||
{
|
||||
dto.Taglines = new List<string> { item.Tagline };
|
||||
dto.Taglines = new string[] { item.Tagline };
|
||||
}
|
||||
|
||||
if (dto.Taglines == null)
|
||||
{
|
||||
dto.Taglines = new List<string>();
|
||||
dto.Taglines = new string[]{};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1130,8 +1119,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
// Include artists that are not in the database yet, e.g., just added via metadata editor
|
||||
//var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
|
||||
dto.ArtistItems = new List<NameIdPair>();
|
||||
dto.ArtistItems.AddRange(hasArtist.Artists
|
||||
dto.ArtistItems = hasArtist.Artists
|
||||
//.Except(foundArtists, new DistinctNameComparer())
|
||||
.Select(i =>
|
||||
{
|
||||
|
@ -1156,7 +1144,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
return null;
|
||||
|
||||
}).Where(i => i != null));
|
||||
}).Where(i => i != null).ToArray();
|
||||
}
|
||||
|
||||
var hasAlbumArtist = item as IHasAlbumArtist;
|
||||
|
@ -1182,8 +1170,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
// })
|
||||
// .ToList();
|
||||
|
||||
dto.AlbumArtists = new List<NameIdPair>();
|
||||
dto.AlbumArtists.AddRange(hasAlbumArtist.AlbumArtists
|
||||
dto.AlbumArtists = hasAlbumArtist.AlbumArtists
|
||||
//.Except(foundArtists, new DistinctNameComparer())
|
||||
.Select(i =>
|
||||
{
|
||||
|
@ -1208,7 +1195,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
return null;
|
||||
|
||||
}).Where(i => i != null));
|
||||
}).Where(i => i != null).ToArray();
|
||||
}
|
||||
|
||||
// Add video info
|
||||
|
@ -1224,9 +1211,9 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.HasSubtitles = video.HasSubtitles;
|
||||
}
|
||||
|
||||
if (video.AdditionalParts.Count != 0)
|
||||
if (video.AdditionalParts.Length != 0)
|
||||
{
|
||||
dto.PartCount = video.AdditionalParts.Count + 1;
|
||||
dto.PartCount = video.AdditionalParts.Length + 1;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.MediaSourceCount))
|
||||
|
@ -1276,7 +1263,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
var hasSpecialFeatures = item as IHasSpecialFeatures;
|
||||
if (hasSpecialFeatures != null)
|
||||
{
|
||||
var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
|
||||
var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Length;
|
||||
|
||||
if (specialFeatureCount > 0)
|
||||
{
|
||||
|
@ -1321,15 +1308,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
Series episodeSeries = null;
|
||||
|
||||
if (fields.Contains(ItemFields.SeriesGenres))
|
||||
{
|
||||
episodeSeries = episodeSeries ?? episode.Series;
|
||||
if (episodeSeries != null)
|
||||
{
|
||||
dto.SeriesGenres = episodeSeries.Genres.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
//if (fields.Contains(ItemFields.SeriesPrimaryImage))
|
||||
{
|
||||
episodeSeries = episodeSeries ?? episode.Series;
|
||||
|
@ -1345,27 +1323,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
if (episodeSeries != null)
|
||||
{
|
||||
dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(dto.SeriesStudio))
|
||||
{
|
||||
try
|
||||
{
|
||||
var studio = _libraryManager.GetStudio(dto.SeriesStudio);
|
||||
|
||||
if (studio != null)
|
||||
{
|
||||
dto.SeriesStudioInfo = new StudioDto
|
||||
{
|
||||
Name = dto.SeriesStudio,
|
||||
Id = studio.Id.ToString("N"),
|
||||
PrimaryImageTag = GetImageCacheTag(studio, ImageType.Primary)
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1440,9 +1397,9 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
if (fields.Contains(ItemFields.ProductionLocations))
|
||||
{
|
||||
if (item.ProductionLocations.Count > 0 || item is Movie)
|
||||
if (item.ProductionLocations.Length > 0 || item is Movie)
|
||||
{
|
||||
dto.ProductionLocations = item.ProductionLocations.ToArray();
|
||||
dto.ProductionLocations = item.ProductionLocations;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1509,7 +1466,9 @@ namespace Emby.Server.Implementations.Dto
|
|||
BaseItem parent = null;
|
||||
var isFirst = true;
|
||||
|
||||
while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) &&
|
||||
var imageTags = dto.ImageTags;
|
||||
|
||||
while (((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0) || parent is Series) &&
|
||||
(parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null)
|
||||
{
|
||||
if (parent == null)
|
||||
|
@ -1519,7 +1478,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
var allImages = parent.ImageInfos;
|
||||
|
||||
if (logoLimit > 0 && !dto.HasLogo && dto.ParentLogoItemId == null)
|
||||
if (logoLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && dto.ParentLogoItemId == null)
|
||||
{
|
||||
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
|
||||
|
||||
|
@ -1529,7 +1488,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.ParentLogoImageTag = GetImageCacheTag(parent, image);
|
||||
}
|
||||
}
|
||||
if (artLimit > 0 && !dto.HasArtImage && dto.ParentArtItemId == null)
|
||||
if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
|
||||
{
|
||||
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
|
||||
|
||||
|
@ -1539,7 +1498,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.ParentArtImageTag = GetImageCacheTag(parent, image);
|
||||
}
|
||||
}
|
||||
if (thumbLimit > 0 && !dto.HasThumb && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
|
||||
if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
|
||||
{
|
||||
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
|
||||
|
||||
|
@ -1549,7 +1508,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.ParentThumbImageTag = GetImageCacheTag(parent, image);
|
||||
}
|
||||
}
|
||||
if (backdropLimit > 0 && !dto.HasBackdrop)
|
||||
if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0)))
|
||||
{
|
||||
var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
|
||||
|
||||
|
@ -1591,12 +1550,12 @@ namespace Emby.Server.Implementations.Dto
|
|||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item)
|
||||
public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasMetadata item)
|
||||
{
|
||||
dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
|
||||
}
|
||||
|
||||
public double? GetPrimaryImageAspectRatio(IHasImages item)
|
||||
public double? GetPrimaryImageAspectRatio(IHasMetadata item)
|
||||
{
|
||||
var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -29,6 +30,7 @@
|
|||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedVersion.cs">
|
||||
|
@ -40,6 +42,8 @@
|
|||
<Compile Include="AppBase\BaseApplicationPaths.cs" />
|
||||
<Compile Include="AppBase\BaseConfigurationManager.cs" />
|
||||
<Compile Include="AppBase\ConfigurationHelper.cs" />
|
||||
<Compile Include="ApplicationHost.cs" />
|
||||
<Compile Include="ApplicationPathHelper.cs" />
|
||||
<Compile Include="Branding\BrandingConfigurationFactory.cs" />
|
||||
<Compile Include="Browser\BrowserLauncher.cs" />
|
||||
<Compile Include="Channels\ChannelConfigurations.cs" />
|
||||
|
@ -52,9 +56,26 @@
|
|||
<Compile Include="Collections\CollectionManager.cs" />
|
||||
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
|
||||
<Compile Include="Configuration\ServerConfigurationManager.cs" />
|
||||
<Compile Include="Cryptography\ASN1.cs" />
|
||||
<Compile Include="Cryptography\ASN1Convert.cs" />
|
||||
<Compile Include="Cryptography\BitConverterLE.cs" />
|
||||
<Compile Include="Cryptography\CertificateGenerator.cs" />
|
||||
<Compile Include="Cryptography\CryptoConvert.cs" />
|
||||
<Compile Include="Cryptography\PfxGenerator.cs" />
|
||||
<Compile Include="Cryptography\PKCS1.cs" />
|
||||
<Compile Include="Cryptography\PKCS12.cs" />
|
||||
<Compile Include="Cryptography\PKCS7.cs" />
|
||||
<Compile Include="Cryptography\PKCS8.cs" />
|
||||
<Compile Include="Cryptography\X501Name.cs" />
|
||||
<Compile Include="Cryptography\X509Builder.cs" />
|
||||
<Compile Include="Cryptography\X509Certificate.cs" />
|
||||
<Compile Include="Cryptography\X509CertificateBuilder.cs" />
|
||||
<Compile Include="Cryptography\X509CertificateCollection.cs" />
|
||||
<Compile Include="Cryptography\X509Extension.cs" />
|
||||
<Compile Include="Cryptography\X509Extensions.cs" />
|
||||
<Compile Include="Cryptography\X520Attributes.cs" />
|
||||
<Compile Include="Data\ManagedConnection.cs" />
|
||||
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
|
||||
<Compile Include="Data\SqliteFileOrganizationRepository.cs" />
|
||||
<Compile Include="Data\SqliteItemRepository.cs" />
|
||||
<Compile Include="Data\SqliteUserDataRepository.cs" />
|
||||
<Compile Include="Data\SqliteUserRepository.cs" />
|
||||
|
@ -64,6 +85,7 @@
|
|||
<Compile Include="Devices\DeviceRepository.cs" />
|
||||
<Compile Include="Dto\DtoService.cs" />
|
||||
<Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
|
||||
<Compile Include="EntryPoints\ExternalPortForwarding.cs" />
|
||||
<Compile Include="EntryPoints\KeepServerAwake.cs" />
|
||||
<Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
|
||||
<Compile Include="EntryPoints\LoadRegistrations.cs" />
|
||||
|
@ -79,13 +101,7 @@
|
|||
<Compile Include="FFMpeg\FFMpegInfo.cs" />
|
||||
<Compile Include="FFMpeg\FFMpegInstallInfo.cs" />
|
||||
<Compile Include="FFMpeg\FFMpegLoader.cs" />
|
||||
<Compile Include="FileOrganization\EpisodeFileOrganizer.cs" />
|
||||
<Compile Include="FileOrganization\Extensions.cs" />
|
||||
<Compile Include="FileOrganization\FileOrganizationNotifier.cs" />
|
||||
<Compile Include="FileOrganization\FileOrganizationService.cs" />
|
||||
<Compile Include="FileOrganization\NameUtils.cs" />
|
||||
<Compile Include="FileOrganization\OrganizerScheduledTask.cs" />
|
||||
<Compile Include="FileOrganization\TvFolderOrganizer.cs" />
|
||||
<Compile Include="HttpServerFactory.cs" />
|
||||
<Compile Include="HttpServer\FileWriter.cs" />
|
||||
<Compile Include="HttpServer\HttpListenerHost.cs" />
|
||||
<Compile Include="HttpServer\HttpResultFactory.cs" />
|
||||
|
@ -107,7 +123,9 @@
|
|||
<Compile Include="Images\BaseDynamicImageProvider.cs" />
|
||||
<Compile Include="IO\AsyncStreamCopier.cs" />
|
||||
<Compile Include="IO\FileRefresher.cs" />
|
||||
<Compile Include="IO\LibraryMonitor.cs" />
|
||||
<Compile Include="IO\MbLinkShortcutHandler.cs" />
|
||||
<Compile Include="IO\MemoryStreamProvider.cs" />
|
||||
<Compile Include="IO\ThrottledStream.cs" />
|
||||
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
|
||||
<Compile Include="Library\LibraryManager.cs" />
|
||||
|
@ -178,6 +196,8 @@
|
|||
<Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
|
||||
<Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
|
||||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="Localization\TextLocalizer.cs" />
|
||||
<Compile Include="Logging\ConsoleLogger.cs" />
|
||||
<Compile Include="Logging\UnhandledExceptionWriter.cs" />
|
||||
<Compile Include="MediaEncoder\EncodingManager.cs" />
|
||||
<Compile Include="Migrations\IVersionMigration.cs" />
|
||||
|
@ -229,7 +249,6 @@
|
|||
<Compile Include="Social\SharingManager.cs" />
|
||||
<Compile Include="Social\SharingRepository.cs" />
|
||||
<Compile Include="Sorting\AiredEpisodeOrderComparer.cs" />
|
||||
<Compile Include="Sorting\AirTimeComparer.cs" />
|
||||
<Compile Include="Sorting\AlbumArtistComparer.cs" />
|
||||
<Compile Include="Sorting\AlbumComparer.cs" />
|
||||
<Compile Include="Sorting\AlphanumComparator.cs" />
|
||||
|
@ -257,6 +276,7 @@
|
|||
<Compile Include="Sorting\StartDateComparer.cs" />
|
||||
<Compile Include="Sorting\StudioComparer.cs" />
|
||||
<Compile Include="StartupOptions.cs" />
|
||||
<Compile Include="SystemEvents.cs" />
|
||||
<Compile Include="TV\SeriesPostScanTask.cs" />
|
||||
<Compile Include="TV\TVSeriesManager.cs" />
|
||||
<Compile Include="Udp\UdpServer.cs" />
|
||||
|
@ -268,6 +288,26 @@
|
|||
<EmbeddedResource Include="Localization\iso6392.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
|
||||
<Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
|
||||
<Name>Emby.Common.Implementations</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
|
||||
<Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
|
||||
<Name>Emby.Dlna</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
|
||||
<Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
|
||||
<Name>Emby.Drawing</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
|
||||
<Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
|
||||
<Name>Emby.Photos</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
|
||||
<Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
|
||||
<Name>MediaBrowser.Api</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
|
@ -276,6 +316,10 @@
|
|||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
|
||||
<Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
|
||||
<Name>MediaBrowser.LocalMetadata</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
|
@ -288,10 +332,29 @@
|
|||
<Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
|
||||
<Name>MediaBrowser.Server.Implementations</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
|
||||
<Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
|
||||
<Name>MediaBrowser.WebDashboard</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
|
||||
<Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
|
||||
<Name>MediaBrowser.XbmcMetadata</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
|
||||
<Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
|
||||
<Name>Mono.Nat</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
|
||||
<Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
|
||||
<Name>OpenSubtitlesHandler</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
|
||||
<Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
|
||||
<Name>SocketHttpListener</Name>
|
||||
</ProjectReference>
|
||||
<Reference Include="Emby.Server.MediaEncoding">
|
||||
<HintPath>..\ThirdParty\emby\Emby.Server.MediaEncoding.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -300,6 +363,16 @@
|
|||
<HintPath>..\packages\MediaBrowser.Naming.1.0.5\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCL.pretty, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -307,10 +380,10 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
@ -421,6 +494,9 @@
|
|||
<ItemGroup>
|
||||
<EmbeddedResource Include="Localization\Ratings\es.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Localization\Ratings\ro.txt" />
|
||||
</ItemGroup>
|
||||
<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.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -11,9 +12,9 @@ using MediaBrowser.Model.Events;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Mono.Nat;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Core.EntryPoints
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
public class ExternalPortForwarding : IServerEntryPoint
|
||||
{
|
||||
|
@ -50,7 +51,7 @@ namespace Emby.Server.Core.EntryPoints
|
|||
values.Add(config.EnableHttps.ToString());
|
||||
values.Add(_appHost.EnableHttps.ToString());
|
||||
|
||||
return string.Join("|", values.ToArray());
|
||||
return string.Join("|", values.ToArray(values.Count));
|
||||
}
|
||||
|
||||
void _config_ConfigurationUpdated(object sender, EventArgs e)
|
|
@ -12,6 +12,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
|
@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
session.ApplicationVersion
|
||||
};
|
||||
|
||||
var key = string.Join("_", keys.ToArray()).GetMD5();
|
||||
var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5();
|
||||
|
||||
_apps.GetOrAdd(key, guid => GetNewClientInfo(session));
|
||||
}
|
||||
|
|
|
@ -1,813 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Naming.TV;
|
||||
using EpisodeInfo = MediaBrowser.Controller.Providers.EpisodeInfo;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public class EpisodeFileOrganizer
|
||||
{
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager)
|
||||
{
|
||||
_organizationService = organizationService;
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, AutoOrganizeOptions options, bool overwriteExisting, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.Info("Sorting file {0}", path);
|
||||
|
||||
var result = new FileOrganizationResult
|
||||
{
|
||||
Date = DateTime.UtcNow,
|
||||
OriginalPath = path,
|
||||
OriginalFileName = Path.GetFileName(path),
|
||||
Type = FileOrganizerType.Episode,
|
||||
FileSize = _fileSystem.GetFileInfo(path).Length
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (_libraryMonitor.IsPathLocked(path))
|
||||
{
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = "Path is locked by other processes. Please try again later.";
|
||||
return result;
|
||||
}
|
||||
|
||||
var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
|
||||
var resolver = new EpisodeResolver(namingOptions, new NullLogger());
|
||||
|
||||
var episodeInfo = resolver.Resolve(path, false) ??
|
||||
new MediaBrowser.Naming.TV.EpisodeInfo();
|
||||
|
||||
var seriesName = episodeInfo.SeriesName;
|
||||
|
||||
if (!string.IsNullOrEmpty(seriesName))
|
||||
{
|
||||
var seasonNumber = episodeInfo.SeasonNumber;
|
||||
|
||||
result.ExtractedSeasonNumber = seasonNumber;
|
||||
|
||||
// Passing in true will include a few extra regex's
|
||||
var episodeNumber = episodeInfo.EpisodeNumber;
|
||||
|
||||
result.ExtractedEpisodeNumber = episodeNumber;
|
||||
|
||||
var premiereDate = episodeInfo.IsByDate ?
|
||||
new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) :
|
||||
(DateTime?)null;
|
||||
|
||||
if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue))
|
||||
{
|
||||
if (episodeInfo.IsByDate)
|
||||
{
|
||||
_logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber;
|
||||
|
||||
result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
|
||||
|
||||
await OrganizeEpisode(path,
|
||||
seriesName,
|
||||
seasonNumber,
|
||||
episodeNumber,
|
||||
endingEpisodeNumber,
|
||||
premiereDate,
|
||||
options,
|
||||
overwriteExisting,
|
||||
false,
|
||||
result,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var msg = string.Format("Unable to determine episode number from {0}", path);
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = msg;
|
||||
_logger.Warn(msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var msg = string.Format("Unable to determine series name from {0}", path);
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = msg;
|
||||
_logger.Warn(msg);
|
||||
}
|
||||
|
||||
var previousResult = _organizationService.GetResultBySourcePath(path);
|
||||
|
||||
if (previousResult != null)
|
||||
{
|
||||
// Don't keep saving the same result over and over if nothing has changed
|
||||
if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success)
|
||||
{
|
||||
return previousResult;
|
||||
}
|
||||
}
|
||||
|
||||
await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = _organizationService.GetResult(request.ResultId);
|
||||
|
||||
try
|
||||
{
|
||||
Series series = null;
|
||||
|
||||
if (request.NewSeriesProviderIds.Count > 0)
|
||||
{
|
||||
// We're having a new series here
|
||||
SeriesInfo seriesRequest = new SeriesInfo();
|
||||
seriesRequest.ProviderIds = request.NewSeriesProviderIds;
|
||||
|
||||
var refreshOptions = new MetadataRefreshOptions(_fileSystem);
|
||||
series = new Series();
|
||||
series.Id = Guid.NewGuid();
|
||||
series.Name = request.NewSeriesName;
|
||||
|
||||
int year;
|
||||
if (int.TryParse(request.NewSeriesYear, out year))
|
||||
{
|
||||
series.ProductionYear = year;
|
||||
}
|
||||
|
||||
var seriesFolderName = series.Name;
|
||||
if (series.ProductionYear.HasValue)
|
||||
{
|
||||
seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear);
|
||||
}
|
||||
|
||||
seriesFolderName = _fileSystem.GetValidFilename(seriesFolderName);
|
||||
|
||||
series.Path = Path.Combine(request.TargetFolder, seriesFolderName);
|
||||
|
||||
series.ProviderIds = request.NewSeriesProviderIds;
|
||||
|
||||
await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
// Existing Series
|
||||
series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
|
||||
}
|
||||
|
||||
await OrganizeEpisode(result.OriginalPath,
|
||||
series,
|
||||
request.SeasonNumber,
|
||||
request.EpisodeNumber,
|
||||
request.EndingEpisodeNumber,
|
||||
null,
|
||||
options,
|
||||
true,
|
||||
request.RememberCorrection,
|
||||
result,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = ex.Message;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Task OrganizeEpisode(string sourcePath,
|
||||
string seriesName,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? endingEpiosdeNumber,
|
||||
DateTime? premiereDate,
|
||||
AutoOrganizeOptions options,
|
||||
bool overwriteExisting,
|
||||
bool rememberCorrection,
|
||||
FileOrganizationResult result,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var series = GetMatchingSeries(seriesName, result, options);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
var msg = string.Format("Unable to find series in library matching name {0}", seriesName);
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = msg;
|
||||
_logger.Warn(msg);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
return OrganizeEpisode(sourcePath,
|
||||
series,
|
||||
seasonNumber,
|
||||
episodeNumber,
|
||||
endingEpiosdeNumber,
|
||||
premiereDate,
|
||||
options,
|
||||
overwriteExisting,
|
||||
rememberCorrection,
|
||||
result,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private async Task OrganizeEpisode(string sourcePath,
|
||||
Series series,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? endingEpiosdeNumber,
|
||||
DateTime? premiereDate,
|
||||
AutoOrganizeOptions options,
|
||||
bool overwriteExisting,
|
||||
bool rememberCorrection,
|
||||
FileOrganizationResult result,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path);
|
||||
|
||||
var originalExtractedSeriesString = result.ExtractedName;
|
||||
|
||||
bool isNew = string.IsNullOrWhiteSpace(result.Id);
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
await _organizationService.SaveResult(result, cancellationToken);
|
||||
}
|
||||
|
||||
if (!_organizationService.AddToInProgressList(result, isNew))
|
||||
{
|
||||
throw new Exception("File is currently processed otherwise. Please try again later.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Proceed to sort the file
|
||||
var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (string.IsNullOrEmpty(newPath))
|
||||
{
|
||||
var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
_logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath);
|
||||
result.TargetPath = newPath;
|
||||
|
||||
var fileExists = _fileSystem.FileExists(result.TargetPath);
|
||||
var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber);
|
||||
|
||||
if (!overwriteExisting)
|
||||
{
|
||||
if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
|
||||
{
|
||||
var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath);
|
||||
_logger.Info(msg);
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = msg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileExists)
|
||||
{
|
||||
var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath);
|
||||
_logger.Info(msg);
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = msg;
|
||||
result.TargetPath = newPath;
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherDuplicatePaths.Count > 0)
|
||||
{
|
||||
var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths));
|
||||
_logger.Info(msg);
|
||||
result.Status = FileSortingStatus.SkippedExisting;
|
||||
result.StatusMessage = msg;
|
||||
result.DuplicatePaths = otherDuplicatePaths;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PerformFileSorting(options.TvOptions, result);
|
||||
|
||||
if (overwriteExisting)
|
||||
{
|
||||
var hasRenamedFiles = false;
|
||||
|
||||
foreach (var path in otherDuplicatePaths)
|
||||
{
|
||||
_logger.Debug("Removing duplicate episode {0}", path);
|
||||
|
||||
_libraryMonitor.ReportFileSystemChangeBeginning(path);
|
||||
|
||||
var renameRelatedFiles = !hasRenamedFiles &&
|
||||
string.Equals(_fileSystem.GetDirectoryName(path), _fileSystem.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (renameRelatedFiles)
|
||||
{
|
||||
hasRenamedFiles = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DeleteLibraryFile(path, renameRelatedFiles, result.TargetPath);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.ErrorException("Error removing duplicate episode", ex, path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(path, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = ex.Message;
|
||||
_logger.Warn(ex.Message);
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_organizationService.RemoveFromInprogressList(result);
|
||||
}
|
||||
|
||||
if (rememberCorrection)
|
||||
{
|
||||
SaveSmartMatchString(originalExtractedSeriesString, series, options);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveSmartMatchString(string matchString, Series series, AutoOrganizeOptions options)
|
||||
{
|
||||
if (string.IsNullOrEmpty(matchString) || matchString.Length < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, series.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
info = new SmartMatchInfo();
|
||||
info.ItemName = series.Name;
|
||||
info.OrganizerType = FileOrganizerType.Episode;
|
||||
info.DisplayName = series.Name;
|
||||
var list = options.SmartMatchInfos.ToList();
|
||||
list.Add(info);
|
||||
options.SmartMatchInfos = list.ToArray();
|
||||
}
|
||||
|
||||
if (!info.MatchStrings.Contains(matchString, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var list = info.MatchStrings.ToList();
|
||||
list.Add(matchString);
|
||||
info.MatchStrings = list.ToArray();
|
||||
_config.SaveAutoOrganizeOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteLibraryFile(string path, bool renameRelatedFiles, string targetPath)
|
||||
{
|
||||
_fileSystem.DeleteFile(path);
|
||||
|
||||
if (!renameRelatedFiles)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Now find other files
|
||||
var originalFilenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
|
||||
var directory = _fileSystem.GetDirectoryName(path);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(originalFilenameWithoutExtension) && !string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
// Get all related files, e.g. metadata, images, etc
|
||||
var files = _fileSystem.GetFilePaths(directory)
|
||||
.Where(i => (Path.GetFileNameWithoutExtension(i) ?? string.Empty).StartsWith(originalFilenameWithoutExtension, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
var targetFilenameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
directory = _fileSystem.GetDirectoryName(file);
|
||||
var filename = Path.GetFileName(file);
|
||||
|
||||
filename = filename.Replace(originalFilenameWithoutExtension, targetFilenameWithoutExtension,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var destination = Path.Combine(directory, filename);
|
||||
|
||||
_fileSystem.MoveFile(file, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetOtherDuplicatePaths(string targetPath,
|
||||
Series series,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? endingEpisodeNumber)
|
||||
{
|
||||
// TODO: Support date-naming?
|
||||
if (!seasonNumber.HasValue || !episodeNumber.HasValue)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
var episodePaths = series.GetRecursiveChildren(i => i is Episode)
|
||||
.OfType<Episode>()
|
||||
.Where(i =>
|
||||
{
|
||||
var locationType = i.LocationType;
|
||||
|
||||
// Must be file system based and match exactly
|
||||
if (locationType != LocationType.Remote &&
|
||||
locationType != LocationType.Virtual &&
|
||||
i.ParentIndexNumber.HasValue &&
|
||||
i.ParentIndexNumber.Value == seasonNumber &&
|
||||
i.IndexNumber.HasValue &&
|
||||
i.IndexNumber.Value == episodeNumber)
|
||||
{
|
||||
|
||||
if (endingEpisodeNumber.HasValue || i.IndexNumberEnd.HasValue)
|
||||
{
|
||||
return endingEpisodeNumber.HasValue && i.IndexNumberEnd.HasValue &&
|
||||
endingEpisodeNumber.Value == i.IndexNumberEnd.Value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.Select(i => i.Path)
|
||||
.ToList();
|
||||
|
||||
var folder = _fileSystem.GetDirectoryName(targetPath);
|
||||
var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath);
|
||||
|
||||
try
|
||||
{
|
||||
var filesOfOtherExtensions = _fileSystem.GetFilePaths(folder)
|
||||
.Where(i => _libraryManager.IsVideoFile(i) && string.Equals(_fileSystem.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
episodePaths.AddRange(filesOfOtherExtensions);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// No big deal. Maybe the season folder doesn't already exist.
|
||||
}
|
||||
|
||||
return episodePaths.Where(i => !string.Equals(i, targetPath, StringComparison.OrdinalIgnoreCase))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
|
||||
{
|
||||
// We should probably handle this earlier so that we never even make it this far
|
||||
if (string.Equals(result.OriginalPath, result.TargetPath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(result.TargetPath));
|
||||
|
||||
var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath);
|
||||
|
||||
try
|
||||
{
|
||||
if (targetAlreadyExists || options.CopyOriginalFile)
|
||||
{
|
||||
_fileSystem.CopyFile(result.OriginalPath, result.TargetPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileSystem.MoveFile(result.OriginalPath, result.TargetPath);
|
||||
}
|
||||
|
||||
result.Status = FileSortingStatus.Success;
|
||||
result.StatusMessage = string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMsg = string.Format("Failed to move file from {0} to {1}: {2}", result.OriginalPath, result.TargetPath, ex.Message);
|
||||
|
||||
result.Status = FileSortingStatus.Failure;
|
||||
result.StatusMessage = errorMsg;
|
||||
_logger.ErrorException(errorMsg, ex);
|
||||
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
|
||||
}
|
||||
|
||||
if (targetAlreadyExists && !options.CopyOriginalFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileSystem.DeleteFile(result.OriginalPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Series GetMatchingSeries(string seriesName, FileOrganizationResult result, AutoOrganizeOptions options)
|
||||
{
|
||||
var parsedName = _libraryManager.ParseName(seriesName);
|
||||
|
||||
var yearInName = parsedName.Year;
|
||||
var nameWithoutYear = parsedName.Name;
|
||||
|
||||
result.ExtractedName = nameWithoutYear;
|
||||
result.ExtractedYear = yearInName;
|
||||
|
||||
var series = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Series).Name },
|
||||
Recursive = true,
|
||||
DtoOptions = new DtoOptions(true)
|
||||
})
|
||||
.Cast<Series>()
|
||||
.Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i))
|
||||
.Where(i => i.Item2 > 0)
|
||||
.OrderByDescending(i => i.Item2)
|
||||
.Select(i => i.Item1)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(e => e.MatchStrings.Contains(nameWithoutYear, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
series = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { typeof(Series).Name },
|
||||
Recursive = true,
|
||||
Name = info.ItemName,
|
||||
DtoOptions = new DtoOptions(true)
|
||||
|
||||
}).Cast<Series>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new path.
|
||||
/// </summary>
|
||||
/// <param name="sourcePath">The source path.</param>
|
||||
/// <param name="series">The series.</param>
|
||||
/// <param name="seasonNumber">The season number.</param>
|
||||
/// <param name="episodeNumber">The episode number.</param>
|
||||
/// <param name="endingEpisodeNumber">The ending episode number.</param>
|
||||
/// <param name="premiereDate">The premiere date.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private async Task<string> GetNewPath(string sourcePath,
|
||||
Series series,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? endingEpisodeNumber,
|
||||
DateTime? premiereDate,
|
||||
TvFileOrganizationOptions options,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var episodeInfo = new EpisodeInfo
|
||||
{
|
||||
IndexNumber = episodeNumber,
|
||||
IndexNumberEnd = endingEpisodeNumber,
|
||||
MetadataCountryCode = series.GetPreferredMetadataCountryCode(),
|
||||
MetadataLanguage = series.GetPreferredMetadataLanguage(),
|
||||
ParentIndexNumber = seasonNumber,
|
||||
SeriesProviderIds = series.ProviderIds,
|
||||
PremiereDate = premiereDate
|
||||
};
|
||||
|
||||
var searchResults = await _providerManager.GetRemoteSearchResults<Episode, EpisodeInfo>(new RemoteSearchQuery<EpisodeInfo>
|
||||
{
|
||||
SearchInfo = episodeInfo
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var episode = searchResults.FirstOrDefault();
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
|
||||
_logger.Warn(msg);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
var episodeName = episode.Name;
|
||||
|
||||
//if (string.IsNullOrWhiteSpace(episodeName))
|
||||
//{
|
||||
// var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
|
||||
// _logger.Warn(msg);
|
||||
// return null;
|
||||
//}
|
||||
|
||||
seasonNumber = seasonNumber ?? episode.ParentIndexNumber;
|
||||
episodeNumber = episodeNumber ?? episode.IndexNumber;
|
||||
|
||||
var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options);
|
||||
|
||||
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options);
|
||||
|
||||
if (string.IsNullOrEmpty(episodeFileName))
|
||||
{
|
||||
// cause failure
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
newPath = Path.Combine(newPath, episodeFileName);
|
||||
|
||||
return newPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the season folder path.
|
||||
/// </summary>
|
||||
/// <param name="series">The series.</param>
|
||||
/// <param name="seasonNumber">The season number.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetSeasonFolderPath(Series series, int seasonNumber, TvFileOrganizationOptions options)
|
||||
{
|
||||
// If there's already a season folder, use that
|
||||
var season = series
|
||||
.GetRecursiveChildren(i => i is Season && i.LocationType == LocationType.FileSystem && i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (season != null)
|
||||
{
|
||||
return season.Path;
|
||||
}
|
||||
|
||||
var path = series.Path;
|
||||
|
||||
if (series.ContainsEpisodesWithoutSeasonFolders)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
if (seasonNumber == 0)
|
||||
{
|
||||
return Path.Combine(path, _fileSystem.GetValidFilename(options.SeasonZeroFolderName));
|
||||
}
|
||||
|
||||
var seasonFolderName = options.SeasonFolderPattern
|
||||
.Replace("%s", seasonNumber.ToString(_usCulture))
|
||||
.Replace("%0s", seasonNumber.ToString("00", _usCulture))
|
||||
.Replace("%00s", seasonNumber.ToString("000", _usCulture));
|
||||
|
||||
return Path.Combine(path, _fileSystem.GetValidFilename(seasonFolderName));
|
||||
}
|
||||
|
||||
private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options)
|
||||
{
|
||||
seriesName = _fileSystem.GetValidFilename(seriesName).Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(episodeTitle))
|
||||
{
|
||||
episodeTitle = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
episodeTitle = _fileSystem.GetValidFilename(episodeTitle).Trim();
|
||||
}
|
||||
|
||||
var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.');
|
||||
|
||||
var pattern = endingEpisodeNumber.HasValue ? options.MultiEpisodeNamePattern : options.EpisodeNamePattern;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pattern))
|
||||
{
|
||||
throw new Exception("GetEpisodeFileName: Configured episode name pattern is empty!");
|
||||
}
|
||||
|
||||
var result = pattern.Replace("%sn", seriesName)
|
||||
.Replace("%s.n", seriesName.Replace(" ", "."))
|
||||
.Replace("%s_n", seriesName.Replace(" ", "_"))
|
||||
.Replace("%s", seasonNumber.ToString(_usCulture))
|
||||
.Replace("%0s", seasonNumber.ToString("00", _usCulture))
|
||||
.Replace("%00s", seasonNumber.ToString("000", _usCulture))
|
||||
.Replace("%ext", sourceExtension)
|
||||
.Replace("%en", "%#1")
|
||||
.Replace("%e.n", "%#2")
|
||||
.Replace("%e_n", "%#3");
|
||||
|
||||
if (endingEpisodeNumber.HasValue)
|
||||
{
|
||||
result = result.Replace("%ed", endingEpisodeNumber.Value.ToString(_usCulture))
|
||||
.Replace("%0ed", endingEpisodeNumber.Value.ToString("00", _usCulture))
|
||||
.Replace("%00ed", endingEpisodeNumber.Value.ToString("000", _usCulture));
|
||||
}
|
||||
|
||||
result = result.Replace("%e", episodeNumber.ToString(_usCulture))
|
||||
.Replace("%0e", episodeNumber.ToString("00", _usCulture))
|
||||
.Replace("%00e", episodeNumber.ToString("000", _usCulture));
|
||||
|
||||
if (result.Contains("%#"))
|
||||
{
|
||||
result = result.Replace("%#1", episodeTitle)
|
||||
.Replace("%#2", episodeTitle.Replace(" ", "."))
|
||||
.Replace("%#3", episodeTitle.Replace(" ", "_"));
|
||||
}
|
||||
|
||||
// Finally, call GetValidFilename again in case user customized the episode expression with any invalid filename characters
|
||||
return _fileSystem.GetValidFilename(result).Trim();
|
||||
}
|
||||
|
||||
private bool IsSameEpisode(string sourcePath, string newPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sourceFileInfo = _fileSystem.GetFileInfo(sourcePath);
|
||||
var destinationFileInfo = _fileSystem.GetFileInfo(newPath);
|
||||
|
||||
if (sourceFileInfo.Length == destinationFileInfo.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public static class ConfigurationExtension
|
||||
{
|
||||
public static AutoOrganizeOptions GetAutoOrganizeOptions(this IConfigurationManager manager)
|
||||
{
|
||||
return manager.GetConfiguration<AutoOrganizeOptions>("autoorganize");
|
||||
}
|
||||
public static void SaveAutoOrganizeOptions(this IConfigurationManager manager, AutoOrganizeOptions options)
|
||||
{
|
||||
manager.SaveConfiguration("autoorganize", options);
|
||||
}
|
||||
}
|
||||
|
||||
public class AutoOrganizeOptionsFactory : IConfigurationFactory
|
||||
{
|
||||
public IEnumerable<ConfigurationStore> GetConfigurations()
|
||||
{
|
||||
return new List<ConfigurationStore>
|
||||
{
|
||||
new ConfigurationStore
|
||||
{
|
||||
Key = "autoorganize",
|
||||
ConfigurationType = typeof (AutoOrganizeOptions)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SessionInfoWebSocketListener
|
||||
/// </summary>
|
||||
class FileOrganizationNotifier : IServerEntryPoint
|
||||
{
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly ITaskManager _taskManager;
|
||||
|
||||
public FileOrganizationNotifier(ILogger logger, IFileOrganizationService organizationService, ISessionManager sessionManager, ITaskManager taskManager)
|
||||
{
|
||||
_organizationService = organizationService;
|
||||
_sessionManager = sessionManager;
|
||||
_taskManager = taskManager;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_organizationService.ItemAdded += _organizationService_ItemAdded;
|
||||
_organizationService.ItemRemoved += _organizationService_ItemRemoved;
|
||||
_organizationService.ItemUpdated += _organizationService_ItemUpdated;
|
||||
_organizationService.LogReset += _organizationService_LogReset;
|
||||
|
||||
//_taskManager.TaskCompleted += _taskManager_TaskCompleted;
|
||||
}
|
||||
|
||||
private void _organizationService_LogReset(object sender, EventArgs e)
|
||||
{
|
||||
_sessionManager.SendMessageToAdminSessions("AutoOrganize_LogReset", (FileOrganizationResult)null, CancellationToken.None);
|
||||
}
|
||||
|
||||
private void _organizationService_ItemUpdated(object sender, GenericEventArgs<FileOrganizationResult> e)
|
||||
{
|
||||
_sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemUpdated", e.Argument, CancellationToken.None);
|
||||
}
|
||||
|
||||
private void _organizationService_ItemRemoved(object sender, GenericEventArgs<FileOrganizationResult> e)
|
||||
{
|
||||
_sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemRemoved", e.Argument, CancellationToken.None);
|
||||
}
|
||||
|
||||
private void _organizationService_ItemAdded(object sender, GenericEventArgs<FileOrganizationResult> e)
|
||||
{
|
||||
_sessionManager.SendMessageToAdminSessions("AutoOrganize_ItemAdded", e.Argument, CancellationToken.None);
|
||||
}
|
||||
|
||||
//private void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
|
||||
//{
|
||||
// var taskWithKey = e.Task.ScheduledTask as IHasKey;
|
||||
// if (taskWithKey != null && taskWithKey.Key == "AutoOrganize")
|
||||
// {
|
||||
// _sessionManager.SendMessageToAdminSessions("AutoOrganize_TaskCompleted", (FileOrganizationResult)null, CancellationToken.None);
|
||||
// }
|
||||
//}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_organizationService.ItemAdded -= _organizationService_ItemAdded;
|
||||
_organizationService.ItemRemoved -= _organizationService_ItemRemoved;
|
||||
_organizationService.ItemUpdated -= _organizationService_ItemUpdated;
|
||||
_organizationService.LogReset -= _organizationService_LogReset;
|
||||
|
||||
//_taskManager.TaskCompleted -= _taskManager_TaskCompleted;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,283 +0,0 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Common.Events;
|
||||
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public class FileOrganizationService : IFileOrganizationService
|
||||
{
|
||||
private readonly ITaskManager _taskManager;
|
||||
private readonly IFileOrganizationRepository _repo;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly ConcurrentDictionary<string, bool> _inProgressItemIds = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded;
|
||||
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated;
|
||||
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved;
|
||||
public event EventHandler LogReset;
|
||||
|
||||
public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager)
|
||||
{
|
||||
_taskManager = taskManager;
|
||||
_repo = repo;
|
||||
_logger = logger;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_libraryManager = libraryManager;
|
||||
_config = config;
|
||||
_fileSystem = fileSystem;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
public void BeginProcessNewFiles()
|
||||
{
|
||||
_taskManager.CancelIfRunningAndQueue<OrganizerScheduledTask>();
|
||||
}
|
||||
|
||||
public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
|
||||
{
|
||||
if (result == null || string.IsNullOrEmpty(result.OriginalPath))
|
||||
{
|
||||
throw new ArgumentNullException("result");
|
||||
}
|
||||
|
||||
result.Id = result.OriginalPath.GetMD5().ToString("N");
|
||||
|
||||
return _repo.SaveResult(result, cancellationToken);
|
||||
}
|
||||
|
||||
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
|
||||
{
|
||||
var results = _repo.GetResults(query);
|
||||
|
||||
foreach (var result in results.Items)
|
||||
{
|
||||
result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResult(string id)
|
||||
{
|
||||
var result = _repo.GetResult(id);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResultBySourcePath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
|
||||
var id = path.GetMD5().ToString("N");
|
||||
|
||||
return GetResult(id);
|
||||
}
|
||||
|
||||
public async Task DeleteOriginalFile(string resultId)
|
||||
{
|
||||
var result = _repo.GetResult(resultId);
|
||||
|
||||
_logger.Info("Requested to delete {0}", result.OriginalPath);
|
||||
|
||||
if (!AddToInProgressList(result, false))
|
||||
{
|
||||
throw new Exception("Path is currently processed otherwise. Please try again later.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_fileSystem.DeleteFile(result.OriginalPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RemoveFromInprogressList(result);
|
||||
}
|
||||
|
||||
await _repo.Delete(resultId);
|
||||
|
||||
EventHelper.FireEventIfNotNull(ItemRemoved, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
|
||||
}
|
||||
|
||||
private AutoOrganizeOptions GetAutoOrganizeOptions()
|
||||
{
|
||||
return _config.GetAutoOrganizeOptions();
|
||||
}
|
||||
|
||||
public async Task PerformOrganization(string resultId)
|
||||
{
|
||||
var result = _repo.GetResult(resultId);
|
||||
|
||||
if (string.IsNullOrEmpty(result.TargetPath))
|
||||
{
|
||||
throw new ArgumentException("No target path available.");
|
||||
}
|
||||
|
||||
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
||||
_libraryMonitor, _providerManager);
|
||||
|
||||
var organizeResult = await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (organizeResult.Status != FileSortingStatus.Success)
|
||||
{
|
||||
throw new Exception(result.StatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ClearLog()
|
||||
{
|
||||
await _repo.DeleteAll();
|
||||
EventHelper.FireEventIfNotNull(LogReset, this, EventArgs.Empty, _logger);
|
||||
}
|
||||
|
||||
public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
|
||||
{
|
||||
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
|
||||
_libraryMonitor, _providerManager);
|
||||
|
||||
var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
if (result.Status != FileSortingStatus.Success)
|
||||
{
|
||||
throw new Exception(result.StatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
throw new ArgumentNullException("query");
|
||||
}
|
||||
|
||||
var options = GetAutoOrganizeOptions();
|
||||
|
||||
var items = options.SmartMatchInfos.Skip(query.StartIndex ?? 0).Take(query.Limit ?? Int32.MaxValue).ToArray();
|
||||
|
||||
return new QueryResult<SmartMatchInfo>()
|
||||
{
|
||||
Items = items,
|
||||
TotalRecordCount = options.SmartMatchInfos.Length
|
||||
};
|
||||
}
|
||||
|
||||
public void DeleteSmartMatchEntry(string itemName, string matchString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(itemName))
|
||||
{
|
||||
throw new ArgumentNullException("itemName");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(matchString))
|
||||
{
|
||||
throw new ArgumentNullException("matchString");
|
||||
}
|
||||
|
||||
var options = GetAutoOrganizeOptions();
|
||||
|
||||
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, itemName));
|
||||
|
||||
if (info != null && info.MatchStrings.Contains(matchString))
|
||||
{
|
||||
var list = info.MatchStrings.ToList();
|
||||
list.Remove(matchString);
|
||||
info.MatchStrings = list.ToArray();
|
||||
|
||||
if (info.MatchStrings.Length == 0)
|
||||
{
|
||||
var infos = options.SmartMatchInfos.ToList();
|
||||
infos.Remove(info);
|
||||
options.SmartMatchInfos = infos.ToArray();
|
||||
}
|
||||
|
||||
_config.SaveAutoOrganizeOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add a an item to the list of currently processed items.
|
||||
/// </summary>
|
||||
/// <param name="result">The result item.</param>
|
||||
/// <param name="isNewItem">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param>
|
||||
/// <returns>True if the item was added, False if the item is already contained in the list.</returns>
|
||||
public bool AddToInProgressList(FileOrganizationResult result, bool isNewItem)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(result.Id))
|
||||
{
|
||||
result.Id = result.OriginalPath.GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
if (!_inProgressItemIds.TryAdd(result.Id, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result.IsInProgress = true;
|
||||
|
||||
if (isNewItem)
|
||||
{
|
||||
EventHelper.FireEventIfNotNull(ItemAdded, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an item from the list of currently processed items.
|
||||
/// </summary>
|
||||
/// <param name="result">The result item.</param>
|
||||
/// <returns>True if the item was removed, False if the item was not contained in the list.</returns>
|
||||
public bool RemoveFromInprogressList(FileOrganizationResult result)
|
||||
{
|
||||
bool itemValue;
|
||||
var retval = _inProgressItemIds.TryRemove(result.Id, out itemValue);
|
||||
|
||||
result.IsInProgress = false;
|
||||
|
||||
EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public static class NameUtils
|
||||
{
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
internal static Tuple<T, int> GetMatchScore<T>(string sortedName, int? year, T series)
|
||||
where T : BaseItem
|
||||
{
|
||||
var score = 0;
|
||||
|
||||
var seriesNameWithoutYear = series.Name;
|
||||
if (series.ProductionYear.HasValue)
|
||||
{
|
||||
seriesNameWithoutYear = seriesNameWithoutYear.Replace(series.ProductionYear.Value.ToString(UsCulture), String.Empty);
|
||||
}
|
||||
|
||||
if (IsNameMatch(sortedName, seriesNameWithoutYear))
|
||||
{
|
||||
score++;
|
||||
|
||||
if (year.HasValue && series.ProductionYear.HasValue)
|
||||
{
|
||||
if (year.Value == series.ProductionYear.Value)
|
||||
{
|
||||
score++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regardless of name, return a 0 score if the years don't match
|
||||
return new Tuple<T, int>(series, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Tuple<T, int>(series, score);
|
||||
}
|
||||
|
||||
|
||||
private static bool IsNameMatch(string name1, string name2)
|
||||
{
|
||||
name1 = GetComparableName(name1);
|
||||
name2 = GetComparableName(name2);
|
||||
|
||||
return String.Equals(name1, name2, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string GetComparableName(string name)
|
||||
{
|
||||
name = name.RemoveDiacritics();
|
||||
|
||||
name = " " + name + " ";
|
||||
|
||||
name = name.Replace(".", " ")
|
||||
.Replace("_", " ")
|
||||
.Replace(" and ", " ")
|
||||
.Replace(".and.", " ")
|
||||
.Replace("&", " ")
|
||||
.Replace("!", " ")
|
||||
.Replace("(", " ")
|
||||
.Replace(")", " ")
|
||||
.Replace(":", " ")
|
||||
.Replace(",", " ")
|
||||
.Replace("-", " ")
|
||||
.Replace("'", " ")
|
||||
.Replace("[", " ")
|
||||
.Replace("]", " ")
|
||||
.Replace(" a ", String.Empty, StringComparison.OrdinalIgnoreCase)
|
||||
.Replace(" the ", String.Empty, StringComparison.OrdinalIgnoreCase)
|
||||
.Replace(" ", String.Empty);
|
||||
|
||||
return name.Trim();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
|
||||
{
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService, IProviderManager providerManager)
|
||||
{
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_libraryManager = libraryManager;
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_config = config;
|
||||
_organizationService = organizationService;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Organize new media files"; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return "Processes new files available in the configured watch folder."; }
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get { return "Library"; }
|
||||
}
|
||||
|
||||
private AutoOrganizeOptions GetAutoOrganizeOptions()
|
||||
{
|
||||
return _config.GetAutoOrganizeOptions();
|
||||
}
|
||||
|
||||
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
if (GetAutoOrganizeOptions().TvOptions.IsEnabled)
|
||||
{
|
||||
await new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config, _providerManager)
|
||||
.Organize(GetAutoOrganizeOptions(), cancellationToken, progress).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the triggers that define when the task will run
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[] {
|
||||
|
||||
// Every so often
|
||||
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromMinutes(5).Ticks}
|
||||
};
|
||||
}
|
||||
|
||||
public bool IsHidden
|
||||
{
|
||||
get { return !GetAutoOrganizeOptions().TvOptions.IsEnabled; }
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return GetAutoOrganizeOptions().TvOptions.IsEnabled; }
|
||||
}
|
||||
|
||||
public bool IsLogged
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public string Key
|
||||
{
|
||||
get { return "AutoOrganize"; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.FileOrganization
|
||||
{
|
||||
public class TvFolderOrganizer
|
||||
{
|
||||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config, IProviderManager providerManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_organizationService = organizationService;
|
||||
_config = config;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options)
|
||||
{
|
||||
var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
|
||||
|
||||
try
|
||||
{
|
||||
return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error organizing file {0}", ex, fileInfo.Name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsValidWatchLocation(string path, List<string> libraryFolderPaths)
|
||||
{
|
||||
if (IsPathAlreadyInMediaLibrary(path, libraryFolderPaths))
|
||||
{
|
||||
_logger.Info("Folder {0} is not eligible for auto-organize because it is also part of an Emby library", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsPathAlreadyInMediaLibrary(string path, List<string> libraryFolderPaths)
|
||||
{
|
||||
return libraryFolderPaths.Any(i => string.Equals(i, path, StringComparison.Ordinal) || _fileSystem.ContainsSubPath(i, path));
|
||||
}
|
||||
|
||||
public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var libraryFolderPaths = _libraryManager.GetVirtualFolders().SelectMany(i => i.Locations).ToList();
|
||||
|
||||
var watchLocations = options.TvOptions.WatchLocations
|
||||
.Where(i => IsValidWatchLocation(i, libraryFolderPaths))
|
||||
.ToList();
|
||||
|
||||
var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
|
||||
.OrderBy(_fileSystem.GetCreationTimeUtc)
|
||||
.Where(i => EnableOrganization(i, options.TvOptions))
|
||||
.ToList();
|
||||
|
||||
var processedFolders = new HashSet<string>();
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
if (eligibleFiles.Count > 0)
|
||||
{
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var file in eligibleFiles)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
|
||||
_libraryMonitor, _providerManager);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
processedFolders.Add(file.DirectoryName);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error organizing episode {0}", ex, file.FullName);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= eligibleFiles.Count;
|
||||
|
||||
progress.Report(10 + 89 * percent);
|
||||
}
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
progress.Report(99);
|
||||
|
||||
foreach (var path in processedFolders)
|
||||
{
|
||||
var deleteExtensions = options.TvOptions.LeftOverFileExtensionsToDelete
|
||||
.Select(i => i.Trim().TrimStart('.'))
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Select(i => "." + i)
|
||||
.ToList();
|
||||
|
||||
if (deleteExtensions.Count > 0)
|
||||
{
|
||||
DeleteLeftOverFiles(path, deleteExtensions);
|
||||
}
|
||||
|
||||
if (options.TvOptions.DeleteEmptyFolders)
|
||||
{
|
||||
if (!IsWatchFolder(path, watchLocations))
|
||||
{
|
||||
DeleteEmptyFolders(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the files to organize.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>IEnumerable{FileInfo}.</returns>
|
||||
private List<FileSystemMetadata> GetFilesToOrganize(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _fileSystem.GetFiles(path, true)
|
||||
.ToList();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting files from {0}", ex, path);
|
||||
|
||||
return new List<FileSystemMetadata>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the left over files.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="extensions">The extensions.</param>
|
||||
private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions)
|
||||
{
|
||||
var eligibleFiles = _fileSystem.GetFilePaths(path, extensions.ToArray(), false, true)
|
||||
.ToList();
|
||||
|
||||
foreach (var file in eligibleFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileSystem.DeleteFile(file);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error deleting file {0}", ex, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the empty folders.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
private void DeleteEmptyFolders(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var d in _fileSystem.GetDirectoryPaths(path))
|
||||
{
|
||||
DeleteEmptyFolders(d);
|
||||
}
|
||||
|
||||
var entries = _fileSystem.GetFileSystemEntryPaths(path);
|
||||
|
||||
if (!entries.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Debug("Deleting empty directory {0}", path);
|
||||
_fileSystem.DeleteDirectory(path, false);
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
catch (IOException) { }
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given folder path is contained in a folder list
|
||||
/// </summary>
|
||||
/// <param name="path">The folder path to check.</param>
|
||||
/// <param name="watchLocations">A list of folders.</param>
|
||||
private bool IsWatchFolder(string path, IEnumerable<string> watchLocations)
|
||||
{
|
||||
return watchLocations.Contains(path, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -125,13 +125,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
return _appHost.CreateInstance(type);
|
||||
}
|
||||
|
||||
private ServiceController CreateServiceController()
|
||||
{
|
||||
var types = _restServices.Select(r => r.GetType()).ToArray();
|
||||
|
||||
return new ServiceController(() => types);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the request filters. Returns whether or not the request has been handled
|
||||
/// and no more processing should be done.
|
||||
|
@ -186,7 +179,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
attributes.Sort((x, y) => x.Priority - y.Priority);
|
||||
|
||||
return attributes.ToArray();
|
||||
return attributes.ToArray(attributes.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -697,11 +690,13 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
{
|
||||
_restServices.AddRange(services);
|
||||
|
||||
ServiceController = CreateServiceController();
|
||||
ServiceController = new ServiceController();
|
||||
|
||||
_logger.Info("Calling ServiceStack AppHost.Init");
|
||||
|
||||
ServiceController.Init(this);
|
||||
var types = _restServices.Select(r => r.GetType()).ToArray();
|
||||
|
||||
ServiceController.Init(this, types);
|
||||
|
||||
var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
|
||||
foreach (var filter in requestFilters)
|
||||
|
@ -741,7 +736,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
});
|
||||
}
|
||||
|
||||
return routes.ToArray();
|
||||
return routes.ToArray(routes.Count);
|
||||
}
|
||||
|
||||
public Func<string, object> GetParseFn(Type propertyType)
|
||||
|
|
|
@ -6,19 +6,16 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
using Emby.Server.Implementations.Services;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Services;
|
||||
using IRequest = MediaBrowser.Model.Services.IRequest;
|
||||
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
|
||||
using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer
|
||||
{
|
||||
|
@ -193,48 +190,35 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// <returns></returns>
|
||||
public object ToOptimizedResult<T>(IRequest request, T dto)
|
||||
{
|
||||
var compressionType = GetCompressionType(request);
|
||||
if (compressionType == null)
|
||||
var contentType = request.ResponseContentType;
|
||||
|
||||
switch (GetRealContentType(contentType))
|
||||
{
|
||||
var contentType = request.ResponseContentType;
|
||||
case "application/xml":
|
||||
case "text/xml":
|
||||
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
|
||||
return SerializeToXmlString(dto);
|
||||
|
||||
switch (GetRealContentType(contentType))
|
||||
{
|
||||
case "application/xml":
|
||||
case "text/xml":
|
||||
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
|
||||
return SerializeToXmlString(dto);
|
||||
case "application/json":
|
||||
case "text/json":
|
||||
return _jsonSerializer.SerializeToString(dto);
|
||||
default:
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
|
||||
|
||||
case "application/json":
|
||||
case "text/json":
|
||||
return _jsonSerializer.SerializeToString(dto);
|
||||
}
|
||||
writerFn(dto, ms);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetHttpResult(new byte[] { }, contentType, true);
|
||||
}
|
||||
|
||||
return GetHttpResult(ms, contentType, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not use the memoryStreamFactory here, they don't place nice with compression
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var contentType = request.ResponseContentType;
|
||||
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
|
||||
|
||||
writerFn(dto, ms);
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream GetCompressionStream(Stream outputStream, string compressionType)
|
||||
{
|
||||
if (compressionType == "deflate")
|
||||
return new DeflateStream(outputStream, CompressionMode.Compress, true);
|
||||
if (compressionType == "gzip")
|
||||
return new GZipStream(outputStream, CompressionMode.Compress, true);
|
||||
|
||||
throw new NotSupportedException(compressionType);
|
||||
}
|
||||
|
||||
public static string GetRealContentType(string contentType)
|
||||
|
@ -568,123 +552,47 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
var contentType = options.ContentType;
|
||||
var responseHeaders = options.ResponseHeaders;
|
||||
|
||||
var requestedCompressionType = GetCompressionType(requestContext);
|
||||
//var requestedCompressionType = GetCompressionType(requestContext);
|
||||
|
||||
if (!compress || string.IsNullOrEmpty(requestedCompressionType))
|
||||
var rangeHeader = requestContext.Headers.Get("Range");
|
||||
|
||||
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
|
||||
{
|
||||
var rangeHeader = requestContext.Headers.Get("Range");
|
||||
|
||||
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
|
||||
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
||||
{
|
||||
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
|
||||
{
|
||||
OnComplete = options.OnComplete,
|
||||
OnError = options.OnError,
|
||||
FileShare = options.FileShare
|
||||
};
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(rangeHeader))
|
||||
{
|
||||
var stream = await factoryFn().ConfigureAwait(false);
|
||||
|
||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
|
||||
{
|
||||
OnComplete = options.OnComplete
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var stream = await factoryFn().ConfigureAwait(false);
|
||||
|
||||
responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
|
||||
|
||||
if (isHeadRequest)
|
||||
{
|
||||
stream.Dispose();
|
||||
|
||||
return GetHttpResult(new byte[] { }, contentType, true);
|
||||
}
|
||||
|
||||
return new StreamWriter(stream, contentType, _logger)
|
||||
{
|
||||
OnComplete = options.OnComplete,
|
||||
OnError = options.OnError
|
||||
};
|
||||
}
|
||||
OnComplete = options.OnComplete,
|
||||
OnError = options.OnError,
|
||||
FileShare = options.FileShare
|
||||
};
|
||||
}
|
||||
|
||||
using (var stream = await factoryFn().ConfigureAwait(false))
|
||||
if (!string.IsNullOrWhiteSpace(rangeHeader))
|
||||
{
|
||||
return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
var stream = await factoryFn().ConfigureAwait(false);
|
||||
|
||||
private async Task<IHasHeaders> GetCompressedResult(Stream stream,
|
||||
string requestedCompressionType,
|
||||
IDictionary<string, string> responseHeaders,
|
||||
bool isHeadRequest,
|
||||
string contentType)
|
||||
{
|
||||
using (var reader = new MemoryStream())
|
||||
{
|
||||
await stream.CopyToAsync(reader).ConfigureAwait(false);
|
||||
|
||||
reader.Position = 0;
|
||||
var content = reader.ToArray();
|
||||
|
||||
if (content.Length >= 1024)
|
||||
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
|
||||
{
|
||||
content = Compress(content, requestedCompressionType);
|
||||
responseHeaders["Content-Encoding"] = requestedCompressionType;
|
||||
}
|
||||
OnComplete = options.OnComplete
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var stream = await factoryFn().ConfigureAwait(false);
|
||||
|
||||
responseHeaders["Vary"] = "Accept-Encoding";
|
||||
responseHeaders["Content-Length"] = content.Length.ToString(UsCulture);
|
||||
responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
|
||||
|
||||
if (isHeadRequest)
|
||||
{
|
||||
stream.Dispose();
|
||||
|
||||
return GetHttpResult(new byte[] { }, contentType, true);
|
||||
}
|
||||
|
||||
return GetHttpResult(content, contentType, true, responseHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] Compress(byte[] bytes, string compressionType)
|
||||
{
|
||||
if (compressionType == "deflate")
|
||||
return Deflate(bytes);
|
||||
|
||||
if (compressionType == "gzip")
|
||||
return GZip(bytes);
|
||||
|
||||
throw new NotSupportedException(compressionType);
|
||||
}
|
||||
|
||||
private byte[] Deflate(byte[] bytes)
|
||||
{
|
||||
// In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
|
||||
// Which means we must use MemoryStream since you have to use ToArray() on a closed Stream
|
||||
using (var ms = new MemoryStream())
|
||||
using (var zipStream = new DeflateStream(ms, CompressionMode.Compress))
|
||||
{
|
||||
zipStream.Write(bytes, 0, bytes.Length);
|
||||
zipStream.Dispose();
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GZip(byte[] buffer)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var zipStream = new GZipStream(ms, CompressionMode.Compress))
|
||||
{
|
||||
zipStream.Write(buffer, 0, buffer.Length);
|
||||
zipStream.Dispose();
|
||||
|
||||
return ms.ToArray();
|
||||
return new StreamWriter(stream, contentType, _logger)
|
||||
{
|
||||
OnComplete = options.OnComplete,
|
||||
OnError = options.OnError
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using MediaBrowser.Model.Services;
|
||||
using SocketHttpListener.Net;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer
|
||||
{
|
||||
|
@ -29,7 +30,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
else
|
||||
{
|
||||
var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
|
||||
var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray(headers.Count));
|
||||
|
||||
logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
||||
{
|
||||
|
@ -585,7 +586,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
|||
WriteCharBytes(bytes, ch, e);
|
||||
}
|
||||
|
||||
byte[] buf = bytes.ToArray();
|
||||
byte[] buf = bytes.ToArray(bytes.Count);
|
||||
bytes = null;
|
||||
return e.GetString(buf, 0, buf.Length);
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Common.Implementations.Net;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
|
@ -21,7 +19,7 @@ using MediaBrowser.Model.Text;
|
|||
using ServiceStack.Text.Jsv;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
namespace Emby.Server.Core
|
||||
namespace Emby.Server.Implementations
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ServerFactory
|
|
@ -130,14 +130,6 @@ namespace Emby.Server.Implementations.IO
|
|||
paths = _affectedPaths.ToList();
|
||||
}
|
||||
|
||||
// Extend the timer as long as any of the paths are still being written to.
|
||||
if (paths.Any(IsFileLocked))
|
||||
{
|
||||
Logger.Info("Timer extended.");
|
||||
RestartTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Debug("Timer stopped.");
|
||||
|
||||
DisposeTimer();
|
||||
|
@ -229,90 +221,6 @@ namespace Emby.Server.Implementations.IO
|
|||
return item;
|
||||
}
|
||||
|
||||
private bool IsFileLocked(string path)
|
||||
{
|
||||
if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
{
|
||||
// Causing lockups on linux
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only try to open video files
|
||||
if (!_libraryManager.IsVideoFile(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var data = _fileSystem.GetFileSystemInfo(path);
|
||||
|
||||
if (!data.Exists
|
||||
|| data.IsDirectory
|
||||
|
||||
// Opening a writable stream will fail with readonly files
|
||||
|| data.IsReadOnly)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error getting file system info for: {0}", ex, path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// In order to determine if the file is being written to, we have to request write access
|
||||
// But if the server only has readonly access, this is going to cause this entire algorithm to fail
|
||||
// So we'll take a best guess about our access level
|
||||
//var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
|
||||
// ? FileAccessMode.ReadWrite
|
||||
// : FileAccessMode.Read;
|
||||
|
||||
var requestedFileAccess = FileAccessMode.Read;
|
||||
try
|
||||
{
|
||||
using (_fileSystem.GetFileStream(path, FileOpenMode.Open, requestedFileAccess, FileShareMode.ReadWrite))
|
||||
{
|
||||
//file is not locked
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
// File may have been deleted
|
||||
return false;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// File may have been deleted
|
||||
return false;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
Logger.Debug("No write permission for: {0}.", path);
|
||||
return false;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
//the file is unavailable because it is:
|
||||
//still being written to
|
||||
//or being processed by another thread
|
||||
//or does not exist (has already been processed)
|
||||
Logger.Debug("{0} is locked.", path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error determining if file is locked: {0}", ex, path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeTimer()
|
||||
{
|
||||
lock (_timerLock)
|
||||
|
|
|
@ -13,9 +13,8 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Emby.Server.Implementations.IO;
|
||||
|
||||
namespace Emby.Server.Core.IO
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class LibraryMonitor : ILibraryMonitor
|
||||
{
|
|
@ -2,7 +2,7 @@
|
|||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.IO;
|
||||
|
||||
namespace Emby.Server.Core.IO
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class RecyclableMemoryStreamProvider : IMemoryStreamFactory
|
||||
{
|
|
@ -37,12 +37,12 @@ namespace Emby.Server.Implementations.Images
|
|||
ImageProcessor = imageProcessor;
|
||||
}
|
||||
|
||||
protected virtual bool Supports(IHasImages item)
|
||||
protected virtual bool Supports(IHasMetadata item)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
public virtual IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.Images
|
|||
};
|
||||
}
|
||||
|
||||
private IEnumerable<ImageType> GetEnabledImages(IHasImages item)
|
||||
private IEnumerable<ImageType> GetEnabledImages(IHasMetadata item)
|
||||
{
|
||||
//var options = ProviderManager.GetMetadataOptions(item);
|
||||
|
||||
|
@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Images
|
|||
return updateType;
|
||||
}
|
||||
|
||||
protected async Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||
protected async Task<ItemUpdateType> FetchAsync(IHasMetadata item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
var image = item.GetImageInfo(imageType, 0);
|
||||
|
||||
|
@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.Images
|
|||
return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected async Task<ItemUpdateType> FetchToFileInternal(IHasImages item,
|
||||
protected async Task<ItemUpdateType> FetchToFileInternal(IHasMetadata item,
|
||||
List<BaseItem> itemsWithImages,
|
||||
ImageType imageType,
|
||||
CancellationToken cancellationToken)
|
||||
|
@ -132,14 +132,14 @@ namespace Emby.Server.Implementations.Images
|
|||
return ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
|
||||
protected abstract List<BaseItem> GetItemsWithImages(IHasImages item);
|
||||
protected abstract List<BaseItem> GetItemsWithImages(IHasMetadata item);
|
||||
|
||||
protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
|
||||
protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
|
||||
{
|
||||
return CreateCollage(primaryItem, items, outputPath, 640, 360);
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
|
||||
protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasMetadata primaryItem, IEnumerable<BaseItem> items)
|
||||
{
|
||||
return items
|
||||
.Select(i =>
|
||||
|
@ -161,22 +161,22 @@ namespace Emby.Server.Implementations.Images
|
|||
.Where(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
||||
protected string CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
|
||||
protected string CreatePosterCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
|
||||
{
|
||||
return CreateCollage(primaryItem, items, outputPath, 400, 600);
|
||||
}
|
||||
|
||||
protected string CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
|
||||
protected string CreateSquareCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
|
||||
{
|
||||
return CreateCollage(primaryItem, items, outputPath, 600, 600);
|
||||
}
|
||||
|
||||
protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
|
||||
protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
|
||||
{
|
||||
return CreateCollage(primaryItem, items, outputPath, width, height);
|
||||
}
|
||||
|
||||
private string CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
|
||||
private string CreateCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
|
||||
{
|
||||
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
|
||||
|
||||
|
@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Images
|
|||
get { return "Dynamic Image Provider"; }
|
||||
}
|
||||
|
||||
protected virtual string CreateImage(IHasImages item,
|
||||
protected virtual string CreateImage(IHasMetadata item,
|
||||
List<BaseItem> itemsWithImages,
|
||||
string outputPathWithoutExtension,
|
||||
ImageType imageType,
|
||||
|
@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.Images
|
|||
return false;
|
||||
}
|
||||
|
||||
protected bool HasChanged(IHasImages item, ImageType type)
|
||||
protected bool HasChanged(IHasMetadata item, ImageType type)
|
||||
{
|
||||
var image = item.GetImageInfo(type, 0);
|
||||
|
||||
|
@ -293,20 +293,16 @@ namespace Emby.Server.Implementations.Images
|
|||
return true;
|
||||
}
|
||||
|
||||
protected List<BaseItem> GetFinalItems(List<BaseItem> items)
|
||||
protected List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items)
|
||||
{
|
||||
return GetFinalItems(items, 4);
|
||||
}
|
||||
|
||||
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
|
||||
protected virtual List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items, int limit)
|
||||
{
|
||||
// Rotate the images once every x days
|
||||
var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
|
||||
|
||||
return items
|
||||
.OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5())
|
||||
.OrderBy(i => Guid.NewGuid())
|
||||
.Take(limit)
|
||||
.OrderBy(i => i.Name)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
|
|
@ -136,14 +136,6 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <value>The configuration manager.</value>
|
||||
private IServerConfigurationManager ConfigurationManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of items that may be referenced from multiple physical places in the library
|
||||
/// (typically, multiple user roots). We store them here and be sure they all reference a
|
||||
/// single instance.
|
||||
/// </summary>
|
||||
/// <value>The by reference items.</value>
|
||||
private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
|
||||
|
||||
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
|
||||
private readonly Func<IProviderManager> _providerManagerFactory;
|
||||
private readonly Func<IUserViewManager> _userviewManager;
|
||||
|
@ -186,7 +178,6 @@ namespace Emby.Server.Implementations.Library
|
|||
_fileSystem = fileSystem;
|
||||
_providerManagerFactory = providerManagerFactory;
|
||||
_userviewManager = userviewManager;
|
||||
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
|
||||
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
|
||||
|
||||
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
|
||||
|
@ -560,22 +551,6 @@ namespace Emby.Server.Implementations.Library
|
|||
return key.GetMD5();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure supplied item has only one instance throughout
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>The proper instance to the item</returns>
|
||||
public BaseItem GetOrAddByReferenceItem(BaseItem item)
|
||||
{
|
||||
// Add this item to our list if not there already
|
||||
if (!ByReferenceItems.TryAdd(item.Id, item))
|
||||
{
|
||||
// Already there - return the existing reference
|
||||
item = ByReferenceItems[item.Id];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public BaseItem ResolvePath(FileSystemMetadata fileInfo,
|
||||
Folder parent = null)
|
||||
{
|
||||
|
@ -1197,6 +1172,8 @@ namespace Emby.Server.Implementations.Library
|
|||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
await ItemRepository.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1275,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return item;
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
|
||||
{
|
||||
if (query.Recursive && query.ParentId.HasValue)
|
||||
{
|
||||
|
@ -1317,7 +1294,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return ItemRepository.GetItemList(query);
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query)
|
||||
{
|
||||
return GetItemList(query, true);
|
||||
}
|
||||
|
@ -1341,7 +1318,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return ItemRepository.GetCount(query);
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
|
||||
public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
|
||||
{
|
||||
SetTopParentIdsOrAncestors(query, parents);
|
||||
|
||||
|
@ -1515,9 +1492,11 @@ namespace Emby.Server.Implementations.Library
|
|||
return ItemRepository.GetItems(query);
|
||||
}
|
||||
|
||||
var list = ItemRepository.GetItemList(query);
|
||||
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
Items = ItemRepository.GetItemList(query).ToArray()
|
||||
Items = list.ToArray(list.Count)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2395,8 +2374,7 @@ namespace Emby.Server.Implementations.Library
|
|||
var resolver = new EpisodeResolver(GetNamingOptions(),
|
||||
new NullLogger());
|
||||
|
||||
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
|
||||
episode.VideoType == VideoType.HdDvd;
|
||||
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd;
|
||||
|
||||
var locationType = episode.LocationType;
|
||||
|
||||
|
@ -2593,7 +2571,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
var namingOptions = GetNamingOptions();
|
||||
|
||||
var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
|
||||
var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
|
||||
.Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
|
||||
.ToList();
|
||||
|
@ -2611,7 +2589,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var resolvers = new IItemResolver[]
|
||||
{
|
||||
new GenericVideoResolver<Trailer>(this)
|
||||
new GenericVideoResolver<Trailer>(this, _fileSystem)
|
||||
};
|
||||
|
||||
return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)
|
||||
|
@ -2632,7 +2610,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return video;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToList();
|
||||
}).OrderBy(i => i.Path);
|
||||
}
|
||||
|
||||
private static readonly string[] ExtrasSubfolderNames = new[] { "extras", "specials", "shorts", "scenes", "featurettes", "behind the scenes", "deleted scenes", "interviews" };
|
||||
|
@ -2674,7 +2652,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return video;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToList();
|
||||
}).OrderBy(i => i.Path);
|
||||
}
|
||||
|
||||
public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
|
||||
|
@ -2857,7 +2835,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return ItemRepository.UpdatePeople(item.Id, people);
|
||||
}
|
||||
|
||||
public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
|
||||
public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex)
|
||||
{
|
||||
foreach (var url in image.Path.Split('|'))
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.Library
|
|||
Recursive = true,
|
||||
DtoOptions = new DtoOptions(false)
|
||||
|
||||
}).ToArray();
|
||||
});
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
|
@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.Library
|
|||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers)
|
||||
private async Task AssignTrailers(IHasTrailers item, IEnumerable<BaseItem> channelTrailers)
|
||||
{
|
||||
if (item is Game)
|
||||
{
|
||||
|
@ -90,7 +91,7 @@ namespace Emby.Server.Implementations.Library
|
|||
});
|
||||
|
||||
var trailerIds = trailers.Select(i => i.Id)
|
||||
.ToList();
|
||||
.ToArray();
|
||||
|
||||
if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
|
||||
{
|
||||
|
|
|
@ -49,10 +49,9 @@ namespace Emby.Server.Implementations.Library
|
|||
_providers = providers.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
|
||||
public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
|
||||
{
|
||||
var list = _itemRepo.GetMediaStreams(query)
|
||||
.ToList();
|
||||
var list = _itemRepo.GetMediaStreams(query);
|
||||
|
||||
foreach (var stream in list)
|
||||
{
|
||||
|
@ -77,7 +76,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
|
||||
public List<MediaStream> GetMediaStreams(string mediaSourceId)
|
||||
{
|
||||
var list = GetMediaStreams(new MediaStreamQuery
|
||||
{
|
||||
|
@ -87,7 +86,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetMediaStreamsForItem(list);
|
||||
}
|
||||
|
||||
public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
|
||||
public List<MediaStream> GetMediaStreams(Guid itemId)
|
||||
{
|
||||
var list = GetMediaStreams(new MediaStreamQuery
|
||||
{
|
||||
|
@ -97,7 +96,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetMediaStreamsForItem(list);
|
||||
}
|
||||
|
||||
private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
|
||||
private List<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
|
||||
{
|
||||
var list = streams.ToList();
|
||||
|
||||
|
@ -253,7 +252,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
|
||||
public List<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
|
@ -265,7 +264,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return item.GetMediaSources(enablePathSubstitution);
|
||||
}
|
||||
|
||||
var sources = item.GetMediaSources(enablePathSubstitution).ToList();
|
||||
var sources = item.GetMediaSources(enablePathSubstitution);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
|
|
@ -19,27 +19,27 @@ namespace Emby.Server.Implementations.Library
|
|||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
var list = new List<Audio>
|
||||
{
|
||||
item
|
||||
};
|
||||
|
||||
return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions));
|
||||
return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions)).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
var genres = item
|
||||
.GetRecursiveChildren(user, new InternalItemsQuery(user)
|
||||
|
@ -55,12 +55,12 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetInstantMixFromGenres(genres, user, dtoOptions);
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
var genreIds = genres.DistinctNames().Select(i =>
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
return _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
|
@ -92,10 +92,10 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).Cast<Audio>();
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
|
||||
public List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
|
||||
{
|
||||
var genre = item as MusicGenre;
|
||||
if (genre != null)
|
||||
|
@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetInstantMixFromFolder(folder, user, dtoOptions);
|
||||
}
|
||||
|
||||
return new Audio[] { };
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Library
|
|||
var fileInfo = directoryService.GetFile(item.Path);
|
||||
SetDateCreated(item, fileSystem, fileInfo);
|
||||
|
||||
EnsureName(item, fileInfo);
|
||||
EnsureName(item, item.Path, fileInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -73,7 +73,7 @@ namespace Emby.Server.Implementations.Library
|
|||
item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
|
||||
|
||||
// Make sure the item has a name
|
||||
EnsureName(item, args.FileInfo);
|
||||
EnsureName(item, item.Path, args.FileInfo);
|
||||
|
||||
item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
item.GetParents().Any(i => i.IsLocked);
|
||||
|
@ -85,14 +85,14 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <summary>
|
||||
/// Ensures the name.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="fileInfo">The file information.</param>
|
||||
private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
|
||||
private static void EnsureName(BaseItem item, string fullPath, FileSystemMetadata fileInfo)
|
||||
{
|
||||
// If the subclass didn't supply a name, add it here
|
||||
if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
|
||||
if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(fullPath))
|
||||
{
|
||||
item.Name = GetDisplayName(fileInfo.Name, fileInfo.IsDirectory);
|
||||
var fileName = fileInfo == null ? Path.GetFileName(fullPath) : fileInfo.Name;
|
||||
|
||||
item.Name = GetDisplayName(fileName, fileInfo != null && fileInfo.IsDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,11 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (config.UseFileCreationTimeForDateAdded)
|
||||
{
|
||||
item.DateCreated = fileSystem.GetCreationTimeUtc(info);
|
||||
// directoryService.getFile may return null
|
||||
if (info != null)
|
||||
{
|
||||
item.DateCreated = fileSystem.GetCreationTimeUtc(info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers
|
||||
|
@ -18,9 +19,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
where T : Video, new()
|
||||
{
|
||||
protected readonly ILibraryManager LibraryManager;
|
||||
protected readonly IFileSystem FileSystem;
|
||||
|
||||
protected BaseVideoResolver(ILibraryManager libraryManager)
|
||||
protected BaseVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem)
|
||||
{
|
||||
FileSystem = fileSystem;
|
||||
LibraryManager = libraryManager;
|
||||
}
|
||||
|
||||
|
@ -178,11 +181,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
{
|
||||
video.VideoType = VideoType.Dvd;
|
||||
}
|
||||
else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
video.VideoType = VideoType.HdDvd;
|
||||
video.IsHD = true;
|
||||
}
|
||||
else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
video.VideoType = VideoType.BluRay;
|
||||
|
@ -276,7 +274,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
return false;
|
||||
}
|
||||
|
||||
return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
|
||||
return FileSystem.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -23,11 +23,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
/// </summary>
|
||||
public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
|
||||
{
|
||||
public MovieResolver(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
|
@ -74,7 +69,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
|
||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return ResolveVideos<MusicVideo>(parent, files, directoryService, false, collectionType);
|
||||
return ResolveVideos<MusicVideo>(parent, files, directoryService, true, collectionType);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
|
||||
|
@ -164,8 +159,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
IsInMixedFolder = isInMixedFolder,
|
||||
ProductionYear = video.Year,
|
||||
Name = video.Name,
|
||||
AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
|
||||
LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
|
||||
AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToArray(),
|
||||
LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
|
||||
};
|
||||
|
||||
SetVideoType(videoItem, firstVideo);
|
||||
|
@ -452,8 +447,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
|
||||
var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
|
||||
{
|
||||
var subFileEntries = directoryService.GetFileSystemEntries(i)
|
||||
.ToList();
|
||||
var subFileEntries = directoryService.GetFileSystemEntries(i);
|
||||
|
||||
var subfolders = subFileEntries
|
||||
.Where(e => e.IsDirectory)
|
||||
|
@ -509,7 +503,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
{
|
||||
Path = folderPaths[0],
|
||||
|
||||
AdditionalParts = folderPaths.Skip(1).ToList(),
|
||||
AdditionalParts = folderPaths.Skip(1).ToArray(),
|
||||
|
||||
VideoType = videoTypes[0],
|
||||
|
||||
|
@ -547,5 +541,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
|
||||
return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public MovieResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
var filename = Path.GetFileNameWithoutExtension(args.Path);
|
||||
|
||||
// Make sure the image doesn't belong to a video file
|
||||
if (args.DirectoryService.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
|
||||
if (_fileSystem.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.TV;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||
{
|
||||
|
@ -11,10 +12,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
/// </summary>
|
||||
public class EpisodeResolver : BaseVideoResolver<Episode>
|
||||
{
|
||||
public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the specified args.
|
||||
/// </summary>
|
||||
|
@ -76,5 +73,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public EpisodeResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
|
@ -9,11 +10,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
/// </summary>
|
||||
public class VideoResolver : BaseVideoResolver<Video>
|
||||
{
|
||||
public VideoResolver(ILibraryManager libraryManager)
|
||||
: base(libraryManager)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Video Resolve(ItemResolveArgs args)
|
||||
{
|
||||
if (args.Parent != null)
|
||||
|
@ -33,12 +29,16 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
{
|
||||
get { return ResolverPriority.Last; }
|
||||
}
|
||||
|
||||
public VideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class GenericVideoResolver<T> : BaseVideoResolver<T>
|
||||
where T : Video, new ()
|
||||
{
|
||||
public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
|
||||
public GenericVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
@ -163,8 +164,8 @@ namespace Emby.Server.Implementations.Library
|
|||
var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
NameContains = searchTerm,
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
|
||||
Limit = query.Limit,
|
||||
IncludeItemsByName = string.IsNullOrWhiteSpace(query.ParentId),
|
||||
ParentId = string.IsNullOrWhiteSpace(query.ParentId) ? (Guid?)null : new Guid(query.ParentId),
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <param name="user">The user.</param>
|
||||
private void OnUserDeleted(User user)
|
||||
{
|
||||
EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
|
||||
EventHelper.FireEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ using System.Threading.Tasks;
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
@ -231,7 +232,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return list;
|
||||
}
|
||||
|
||||
private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
|
||||
private List<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
|
||||
{
|
||||
var parentId = request.ParentId;
|
||||
|
||||
|
@ -269,7 +270,41 @@ namespace Emby.Server.Implementations.Library
|
|||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
|
||||
var mediaTypes = new List<string>();
|
||||
|
||||
if (includeItemTypes.Length == 0)
|
||||
{
|
||||
foreach (var parent in parents.OfType<ICollectionFolder>())
|
||||
{
|
||||
switch (parent.CollectionType)
|
||||
{
|
||||
case CollectionType.Books:
|
||||
mediaTypes.Add(MediaType.Book);
|
||||
break;
|
||||
case CollectionType.Games:
|
||||
mediaTypes.Add(MediaType.Game);
|
||||
break;
|
||||
case CollectionType.Music:
|
||||
mediaTypes.Add(MediaType.Audio);
|
||||
break;
|
||||
case CollectionType.Photos:
|
||||
mediaTypes.Add(MediaType.Photo);
|
||||
mediaTypes.Add(MediaType.Video);
|
||||
break;
|
||||
case CollectionType.HomeVideos:
|
||||
mediaTypes.Add(MediaType.Photo);
|
||||
mediaTypes.Add(MediaType.Video);
|
||||
break;
|
||||
default:
|
||||
mediaTypes.Add(MediaType.Video);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mediaTypes = mediaTypes.Distinct().ToList();
|
||||
}
|
||||
|
||||
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
|
||||
{
|
||||
typeof(Person).Name,
|
||||
typeof(Studio).Name,
|
||||
|
@ -290,7 +325,8 @@ namespace Emby.Server.Implementations.Library
|
|||
IsVirtualItem = false,
|
||||
Limit = limit * 5,
|
||||
IsPlayed = isPlayed,
|
||||
DtoOptions = options
|
||||
DtoOptions = options,
|
||||
MediaTypes = mediaTypes.ToArray(mediaTypes.Count)
|
||||
};
|
||||
|
||||
if (parents.Count == 0)
|
||||
|
|
|
@ -55,28 +55,21 @@ namespace Emby.Server.Implementations.Library.Validators
|
|||
/// <returns>Task.</returns>
|
||||
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var people = _libraryManager.GetPeople(new InternalPeopleQuery());
|
||||
|
||||
var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var person in people)
|
||||
{
|
||||
dict[person.Name] = true;
|
||||
}
|
||||
var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery());
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
_logger.Debug("Will refresh {0} people", dict.Count);
|
||||
var numPeople = people.Count;
|
||||
|
||||
var numPeople = dict.Count;
|
||||
_logger.Debug("Will refresh {0} people", numPeople);
|
||||
|
||||
foreach (var person in dict)
|
||||
foreach (var person in people)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
var item = _libraryManager.GetPerson(person.Key);
|
||||
var item = _libraryManager.GetPerson(person);
|
||||
|
||||
var options = new MetadataRefreshOptions(_fileSystem)
|
||||
{
|
||||
|
|
|
@ -28,12 +28,12 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
_appHost = appHost;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
|
||||
public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
|
||||
{
|
||||
var liveTvItem = (LiveTvChannel)item;
|
||||
|
||||
|
@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
get { return "Live TV Service Provider"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
public bool Supports(IHasMetadata item)
|
||||
{
|
||||
return item is LiveTvChannel;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ using MediaBrowser.Common.Net;
|
|||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
|
@ -36,7 +35,6 @@ using MediaBrowser.Controller.Entities.TV;
|
|||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
@ -61,7 +59,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
private readonly ILibraryMonitor _libraryMonitor;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IProcessFactory _processFactory;
|
||||
private readonly ISystemEvents _systemEvents;
|
||||
|
@ -74,7 +71,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
|
||||
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, ITimerFactory timerFactory, IProcessFactory processFactory, ISystemEvents systemEvents)
|
||||
public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory, IProcessFactory processFactory, ISystemEvents systemEvents)
|
||||
{
|
||||
Current = this;
|
||||
|
||||
|
@ -86,7 +83,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
_libraryManager = libraryManager;
|
||||
_libraryMonitor = libraryMonitor;
|
||||
_providerManager = providerManager;
|
||||
_organizationService = organizationService;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_processFactory = processFactory;
|
||||
_systemEvents = systemEvents;
|
||||
|
@ -1636,7 +1632,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
return;
|
||||
}
|
||||
|
||||
var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery
|
||||
var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
SortOrder = SortOrder.Descending,
|
||||
|
@ -1646,7 +1642,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
DtoOptions = new DtoOptions(true)
|
||||
|
||||
}))
|
||||
.Items
|
||||
.Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
|
||||
.Skip(seriesTimer.KeepUpTo - 1)
|
||||
.ToList();
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
return "ts";
|
||||
}
|
||||
|
||||
return "mp4";
|
||||
return "mkv";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,9 +207,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
inputModifier += " -fflags " + string.Join("", flags.ToArray());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(GetEncodingOptions().HardwareAccelerationType))
|
||||
var videoStream = mediaSource.VideoStream;
|
||||
var videoDecoder = videoStream == null ? null : new EncodingHelper(_mediaEncoder, _fileSystem, null).GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions());
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(videoDecoder))
|
||||
{
|
||||
inputModifier += " -hwaccel auto";
|
||||
inputModifier += " " + videoDecoder;
|
||||
}
|
||||
|
||||
if (mediaSource.ReadAtNativeFramerate)
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
try
|
||||
{
|
||||
dto.ParentBackdropImageTags = new List<string>
|
||||
dto.ParentBackdropImageTags = new string[]
|
||||
{
|
||||
_imageProcessor.GetImageCacheTag(librarySeries, image)
|
||||
};
|
||||
|
@ -218,14 +218,14 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Count == 0)
|
||||
if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Length == 0)
|
||||
{
|
||||
image = program.GetImageInfo(ImageType.Backdrop, 0);
|
||||
if (image != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
dto.ParentBackdropImageTags = new List<string>
|
||||
dto.ParentBackdropImageTags = new string[]
|
||||
{
|
||||
_imageProcessor.GetImageCacheTag(program, image)
|
||||
};
|
||||
|
@ -406,7 +406,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
return dto;
|
||||
}
|
||||
|
||||
internal string GetImageTag(IHasImages info)
|
||||
internal string GetImageTag(IHasMetadata info)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -173,7 +173,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
|
||||
public async Task<QueryResult<BaseItem>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
|
||||
|
||||
|
@ -208,15 +208,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
|
||||
}
|
||||
|
||||
var channelResult = _libraryManager.GetItemsResult(internalQuery);
|
||||
|
||||
var result = new QueryResult<LiveTvChannel>
|
||||
{
|
||||
Items = channelResult.Items.Cast<LiveTvChannel>().ToArray(),
|
||||
TotalRecordCount = channelResult.TotalRecordCount
|
||||
};
|
||||
|
||||
return result;
|
||||
return _libraryManager.GetItemsResult(internalQuery);
|
||||
}
|
||||
|
||||
public LiveTvChannel GetInternalChannel(string id)
|
||||
|
@ -993,7 +985,9 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var queryResult = _libraryManager.QueryItems(internalQuery);
|
||||
|
||||
var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnArray = returnList.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -1077,7 +1071,9 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var user = _userManager.GetUserById(query.UserId);
|
||||
|
||||
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnArray = returnList.ToArray(returnList.Count);
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -1639,7 +1635,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
MediaTypes = new[] { MediaType.Video },
|
||||
Recursive = true,
|
||||
AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(),
|
||||
AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(folderIds.Count),
|
||||
IsFolder = false,
|
||||
IsVirtualItem = false,
|
||||
Limit = query.Limit,
|
||||
|
@ -1647,9 +1643,9 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
SortOrder = SortOrder.Descending,
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
Genres = genres.ToArray(),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
|
||||
Genres = genres.ToArray(genres.Count),
|
||||
DtoOptions = dtoOptions
|
||||
});
|
||||
}
|
||||
|
@ -1695,17 +1691,20 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
|
||||
AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(folders.Count),
|
||||
Limit = query.Limit,
|
||||
SortBy = new[] { ItemSortBy.DateCreated },
|
||||
SortOrder = SortOrder.Descending,
|
||||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
IncludeItemTypes = includeItemTypes.ToArray(),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(),
|
||||
IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
|
||||
ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
|
||||
DtoOptions = options
|
||||
});
|
||||
|
||||
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
|
||||
.ConfigureAwait(false));
|
||||
|
||||
var returnArray = returnList.ToArray(returnList.Count);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -1845,6 +1844,9 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
|
||||
{
|
||||
var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
|
||||
var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
|
||||
var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
|
||||
var hasServiceName = fields.Contains(ItemFields.ServiceName);
|
||||
|
||||
foreach (var tuple in tuples)
|
||||
{
|
||||
|
@ -1887,7 +1889,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
dto.IsPremiere = program.IsPremiere;
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.ChannelInfo))
|
||||
if (hasChannelInfo || hasChannelImage)
|
||||
{
|
||||
var channel = GetInternalChannel(program.ChannelId);
|
||||
|
||||
|
@ -1897,7 +1899,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
dto.MediaType = channel.MediaType;
|
||||
dto.ChannelNumber = channel.Number;
|
||||
|
||||
if (channel.HasImage(ImageType.Primary))
|
||||
if (hasChannelImage && channel.HasImage(ImageType.Primary))
|
||||
{
|
||||
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
|
||||
}
|
||||
|
@ -1906,7 +1908,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var serviceName = program.ServiceName;
|
||||
|
||||
if (fields.Contains(ItemFields.ServiceName))
|
||||
if (hasServiceName)
|
||||
{
|
||||
dto.ServiceName = serviceName;
|
||||
}
|
||||
|
@ -1954,7 +1956,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
if (dto.MediaSources == null)
|
||||
{
|
||||
dto.MediaSources = recording.GetMediaSources(true).ToList();
|
||||
dto.MediaSources = recording.GetMediaSources(true);
|
||||
}
|
||||
|
||||
if (dto.MediaStreams == null)
|
||||
|
@ -1993,7 +1995,9 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
|
||||
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
|
||||
.ConfigureAwait(false));
|
||||
var returnArray = returnList.ToArray(returnList.Count);
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
|
@ -2081,7 +2085,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var returnArray = returnList
|
||||
.OrderBy(i => i.StartDate)
|
||||
.ToArray();
|
||||
.ToArray(returnList.Count);
|
||||
|
||||
return new QueryResult<TimerInfoDto>
|
||||
{
|
||||
|
@ -2154,7 +2158,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
|
||||
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||
|
||||
EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
|
||||
EventHelper.FireEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
|
||||
{
|
||||
Argument = new TimerEventInfo
|
||||
{
|
||||
|
@ -2177,7 +2181,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
|
||||
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||
|
||||
EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
|
||||
EventHelper.FireEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
|
||||
{
|
||||
Argument = new TimerEventInfo
|
||||
{
|
||||
|
@ -2338,7 +2342,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") },
|
||||
DtoOptions = options
|
||||
|
||||
}).ToList() : new List<BaseItem>();
|
||||
}) : new List<BaseItem>();
|
||||
|
||||
RemoveFields(options);
|
||||
|
||||
|
@ -2347,6 +2351,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var addCurrentProgram = options.AddCurrentProgram;
|
||||
var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
|
||||
var addServiceName = options.Fields.Contains(ItemFields.ServiceName);
|
||||
|
||||
foreach (var tuple in tuples)
|
||||
{
|
||||
|
@ -2356,13 +2361,17 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
dto.Number = channel.Number;
|
||||
dto.ChannelNumber = channel.Number;
|
||||
dto.ChannelType = channel.ChannelType;
|
||||
dto.ServiceName = channel.ServiceName;
|
||||
|
||||
if (addServiceName)
|
||||
{
|
||||
dto.ServiceName = channel.ServiceName;
|
||||
}
|
||||
|
||||
currentChannelsDict[dto.Id] = dto;
|
||||
|
||||
if (addMediaSources)
|
||||
{
|
||||
dto.MediaSources = channel.GetMediaSources(true).ToList();
|
||||
dto.MediaSources = channel.GetMediaSources(true);
|
||||
}
|
||||
|
||||
if (addCurrentProgram)
|
||||
|
@ -2516,7 +2525,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||
_logger.Info("New recording scheduled");
|
||||
|
||||
EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
|
||||
EventHelper.FireEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
|
||||
{
|
||||
Argument = new TimerEventInfo
|
||||
{
|
||||
|
@ -2558,7 +2567,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||
|
||||
EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
|
||||
EventHelper.FireEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
|
||||
{
|
||||
Argument = new TimerEventInfo
|
||||
{
|
||||
|
@ -2697,7 +2706,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
return new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = groups.ToArray(),
|
||||
Items = groups.ToArray(groups.Count),
|
||||
TotalRecordCount = groups.Count
|
||||
};
|
||||
}
|
||||
|
@ -2984,7 +2993,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
Name = tunerChannelId,
|
||||
Value = providerChannelId
|
||||
});
|
||||
listingsProviderInfo.ChannelMappings = list.ToArray();
|
||||
listingsProviderInfo.ChannelMappings = list.ToArray(list.Count);
|
||||
}
|
||||
|
||||
_config.SaveConfiguration("livetv", config);
|
||||
|
|
|
@ -14,6 +14,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.LiveTv
|
||||
{
|
||||
|
@ -78,8 +79,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
var hasMediaSources = (IHasMediaSources)item;
|
||||
|
||||
sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
|
||||
.ToList();
|
||||
sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false);
|
||||
|
||||
forceRequireOpening = true;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
openKeys.Add(item.GetType().Name);
|
||||
openKeys.Add(item.Id.ToString("N"));
|
||||
openKeys.Add(source.Id ?? string.Empty);
|
||||
source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
|
||||
source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray(openKeys.Count));
|
||||
}
|
||||
|
||||
// Dummy this up so that direct play checks can still run
|
||||
|
|
|
@ -19,12 +19,12 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
_liveTvManager = liveTvManager;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
|
||||
{
|
||||
return new[] { ImageType.Primary };
|
||||
}
|
||||
|
||||
public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
|
||||
public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
|
||||
{
|
||||
var liveTvItem = (ILiveTvRecording)item;
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
get { return "Live TV Service Provider"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
public bool Supports(IHasMetadata item)
|
||||
{
|
||||
return item is ILiveTvRecording;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -11,12 +10,10 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.System;
|
||||
|
@ -46,9 +43,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
get { return "M3U Tuner"; }
|
||||
}
|
||||
|
||||
private string GetFullChannelIdPrefix(TunerHostInfo info)
|
||||
{
|
||||
return ChannelIdPrefix + info.Url.GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, !info.EnableTvgId, cancellationToken).ConfigureAwait(false);
|
||||
var channelIdPrefix = GetFullChannelIdPrefix(info);
|
||||
|
||||
var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return result.Cast<ChannelInfo>().ToList();
|
||||
}
|
||||
|
@ -87,9 +91,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
|
||||
{
|
||||
var urlHash = info.Url.GetMD5().ToString("N");
|
||||
var prefix = ChannelIdPrefix + urlHash;
|
||||
if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
var channelIdPrefix = GetFullChannelIdPrefix(info);
|
||||
|
||||
if (!channelId.StartsWith(channelIdPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -32,25 +32,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
_appHost = appHost;
|
||||
}
|
||||
|
||||
public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier, CancellationToken cancellationToken)
|
||||
public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
|
||||
{
|
||||
var urlHash = url.GetMD5().ToString("N");
|
||||
|
||||
// Read the file and display it line by line.
|
||||
using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
|
||||
{
|
||||
return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, enableStreamUrlAsIdentifier);
|
||||
return GetChannels(reader, channelIdPrefix, tunerHostId);
|
||||
}
|
||||
}
|
||||
|
||||
public List<M3UChannel> ParseString(string text, string channelIdPrefix, string tunerHostId)
|
||||
{
|
||||
var urlHash = "text".GetMD5().ToString("N");
|
||||
|
||||
// Read the file and display it line by line.
|
||||
using (var reader = new StringReader(text))
|
||||
{
|
||||
return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, false);
|
||||
return GetChannels(reader, channelIdPrefix, tunerHostId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +66,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
|
||||
const string ExtInfPrefix = "#EXTINF:";
|
||||
private List<M3UChannel> GetChannels(TextReader reader, string urlHash, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier)
|
||||
private List<M3UChannel> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId)
|
||||
{
|
||||
var channels = new List<M3UChannel>();
|
||||
string line;
|
||||
|
@ -97,13 +93,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var channel = GetChannelnfo(extInf, tunerHostId, line);
|
||||
if (string.IsNullOrWhiteSpace(channel.Id) || enableStreamUrlAsIdentifier)
|
||||
if (string.IsNullOrWhiteSpace(channel.Id))
|
||||
{
|
||||
channel.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
|
||||
channel.Id = channelIdPrefix + line.GetMD5().ToString("N");
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.Id = channelIdPrefix + urlHash + channel.Id.GetMD5().ToString("N");
|
||||
channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
channel.Path = line;
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
"ViewTypeTvResume": "Resume",
|
||||
"ViewTypeTvNextUp": "Next Up",
|
||||
"ViewTypeTvLatest": "Latest",
|
||||
"ViewTypeTvShowSeries": "Series",
|
||||
"ViewTypeTvShowSeries": "Shows",
|
||||
"ViewTypeTvGenres": "Genres",
|
||||
"ViewTypeTvFavoriteSeries": "Favorite Series",
|
||||
"ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
|
||||
|
|
|
@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Localization
|
|||
/// Gets the cultures.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{CultureDto}.</returns>
|
||||
public IEnumerable<CultureDto> GetCultures()
|
||||
public List<CultureDto> GetCultures()
|
||||
{
|
||||
var type = GetType();
|
||||
var path = type.Namespace + ".iso6392.txt";
|
||||
|
@ -169,14 +169,14 @@ namespace Emby.Server.Implementations.Localization
|
|||
return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
|
||||
!string.IsNullOrWhiteSpace(i.DisplayName) &&
|
||||
!string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
|
||||
!string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName));
|
||||
!string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the countries.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{CountryInfo}.</returns>
|
||||
public IEnumerable<CountryInfo> GetCountries()
|
||||
public List<CountryInfo> GetCountries()
|
||||
{
|
||||
var type = GetType();
|
||||
var path = type.Namespace + ".countries.json";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
ES-A,1
|
||||
ES-APTA,1
|
||||
ES-7,3
|
||||
ES-12,6
|
||||
ES-16,8
|
||||
|
|
1
Emby.Server.Implementations/Localization/Ratings/ro.txt
Normal file
1
Emby.Server.Implementations/Localization/Ratings/ro.txt
Normal file
|
@ -0,0 +1 @@
|
|||
RO-AG,1
|
|
@ -1,3 +1,4 @@
|
|||
APPROVED,1
|
||||
G,1
|
||||
E,1
|
||||
EC,1
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user