Merge pull request #2815 from MediaBrowser/beta

Beta
pull/1154/head
Luke 7 years ago committed by GitHub
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))
{
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))
var enumNames = Enum.GetNames(typeof(StubType));
foreach (var name in enumNames)
{
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();
_logger.Debug("RestartTimerInactive");
var interval = GetInactiveTimerIntervalMs();
if (_timer != null)
{
_timer.Change(interval, interval);
}
if (_timer != null)
{
_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.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.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.Dlna;
using MediaBrowser.Model.Globalization;
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.Text;
using MediaBrowser.Model.Xml;
using OpenSubtitlesHandler;
using ServiceStack;
using SocketHttpListener.Primitives;
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,50 +190,37 @@ 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))
{
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);
}
}
var contentType = request.ResponseContentType;
// Do not use the memoryStreamFactory here, they don't place nice with compression
using (var ms = new MemoryStream())
switch (GetRealContentType(contentType))
{
var contentType = request.ResponseContentType;
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
case "application/xml":
case "text/xml":
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
return SerializeToXmlString(dto);
writerFn(dto, ms);
case "application/json":
case "text/json":
return _jsonSerializer.SerializeToString(dto);
default:
{
var ms = new MemoryStream();
var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
ms.Position = 0;
writerFn(dto, ms);
ms.Position = 0;
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
{
return GetHttpResult(new byte[] { }, contentType, true);
}
return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
return GetHttpResult(ms, contentType, true);
}
}
}
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)
{
return contentType == null
@ -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))
{
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
};
}
}
var rangeHeader = requestContext.Headers.Get("Range");
using (var stream = await factoryFn().ConfigureAwait(false))
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
{
return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
{
OnComplete = options.OnComplete,
OnError = options.OnError,
FileShare = options.FileShare
};
}
}
private async Task<IHasHeaders> GetCompressedResult(Stream stream,
string requestedCompressionType,
IDictionary<string, string> responseHeaders,
bool isHeadRequest,
string contentType)
{
using (var reader = new MemoryStream())
if (!string.IsNullOrWhiteSpace(rangeHeader))
{
await stream.CopyToAsync(reader).ConfigureAwait(false);
reader.Position = 0;
var content = reader.ToArray();
var stream = await factoryFn().ConfigureAwait(false);
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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save