diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index b93d339ced..df728ee0d3 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
if (request.UserId.HasValue)
{
- items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user);
+ items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user, true);
}
else
{
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 10e56af52c..8497901f63 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -305,7 +305,7 @@ namespace MediaBrowser.Api.UserLibrary
return ((Folder)item).GetRecursiveChildren(user);
}
- return ((Folder)item).GetChildren(user, request.IndexBy);
+ return ((Folder)item).GetChildren(user, true, request.IndexBy);
}
///
@@ -433,7 +433,7 @@ namespace MediaBrowser.Api.UserLibrary
{
var item = DtoBuilder.GetItemByClientId(request.AdjacentTo, _userManager, _libraryManager);
- var allSiblings = item.Parent.GetChildren(user).OrderBy(i => i.SortName).ToList();
+ var allSiblings = item.Parent.GetChildren(user, true).OrderBy(i => i.SortName).ToList();
var index = allSiblings.IndexOf(item);
diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs
index b321df2d18..b921566aa6 100644
--- a/MediaBrowser.Controller/Dto/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs
@@ -127,7 +127,7 @@ namespace MediaBrowser.Controller.Dto
var folder = (Folder)item;
// Skip sorting since all we want is a count
- dto.ChildCount = folder.GetChildren(user).Count();
+ dto.ChildCount = folder.GetChildren(user, true).Count();
SetSpecialCounts(folder, user, dto, _userDataRepository);
}
@@ -555,7 +555,7 @@ namespace MediaBrowser.Controller.Dto
double totalPercentPlayed = 0;
// Loop through each recursive child
- foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder).ToList())
+ foreach (var child in folder.GetRecursiveChildren(user, true).Where(i => !i.IsFolder).ToList())
{
var userdata = userDataRepository.GetUserData(user.Id, child.GetUserDataKey());
@@ -610,11 +610,6 @@ namespace MediaBrowser.Controller.Dto
/// Task.
private async Task AttachPeople(BaseItemDto dto, BaseItem item)
{
- if (item.People == null)
- {
- return;
- }
-
// Ordering by person type to ensure actors and artists are at the front.
// This is taking advantage of the fact that they both begin with A
// This should be improved in the future
@@ -640,7 +635,7 @@ namespace MediaBrowser.Controller.Dto
)).ConfigureAwait(false);
- var dictionary = entities.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+ var dictionary = entities.Where(i => i != null).ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < people.Count; i++)
{
@@ -698,7 +693,7 @@ namespace MediaBrowser.Controller.Dto
)).ConfigureAwait(false);
- var dictionary = entities.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+ var dictionary = entities.Where(i => i != null).ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < studios.Count; i++)
{
@@ -967,7 +962,7 @@ namespace MediaBrowser.Controller.Dto
values.RemoveRange(0, 2);
// Get the IndexFolder
- var indexFolder = parentFolder.GetChildren(user, indexBy).FirstOrDefault(i => i.Id == indexFolderId) as Folder;
+ var indexFolder = parentFolder.GetChildren(user, false, indexBy).FirstOrDefault(i => i.Id == indexFolderId) as Folder;
// Nested index folder
if (values.Count > 0)
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 3202250314..1cbe5b635c 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -617,6 +617,11 @@ namespace MediaBrowser.Controller.Entities
try
{
resolveArgs = ResolveArgs;
+
+ if (!resolveArgs.IsDirectory)
+ {
+ return new List();
+ }
}
catch (IOException ex)
{
@@ -624,11 +629,6 @@ namespace MediaBrowser.Controller.Entities
return new List();
}
- if (!resolveArgs.IsDirectory)
- {
- return new List();
- }
-
var files = new List();
var folder = resolveArgs.GetFileSystemEntryByName(TrailerFolderName);
@@ -687,6 +687,11 @@ namespace MediaBrowser.Controller.Entities
try
{
resolveArgs = ResolveArgs;
+
+ if (!resolveArgs.IsDirectory)
+ {
+ return new List();
+ }
}
catch (IOException ex)
{
@@ -694,11 +699,6 @@ namespace MediaBrowser.Controller.Entities
return new List();
}
- if (!resolveArgs.IsDirectory)
- {
- return new List();
- }
-
var files = new List();
var folder = resolveArgs.GetFileSystemEntryByName(ThemeSongsFolderName);
@@ -747,6 +747,11 @@ namespace MediaBrowser.Controller.Entities
try
{
resolveArgs = ResolveArgs;
+
+ if (!resolveArgs.IsDirectory)
+ {
+ return new List
public class Folder : BaseItem
{
+ public Folder()
+ {
+ LinkedChildren = new List();
+ }
+
///
/// Gets a value indicating whether this instance is folder.
///
@@ -83,6 +89,13 @@ namespace MediaBrowser.Controller.Entities
return (userId + DisplayPreferencesId.ToString()).GetMD5();
}
+ public List LinkedChildren { get; set; }
+
+ protected virtual bool SupportsLinkedChildren
+ {
+ get { return false; }
+ }
+
///
/// Adds the child.
///
@@ -878,10 +891,11 @@ namespace MediaBrowser.Controller.Entities
/// Gets allowed children of an item
///
/// The user.
+ /// if set to true [include linked children].
/// The index by.
/// IEnumerable{BaseItem}.
///
- public virtual IEnumerable GetChildren(User user, string indexBy = null)
+ public virtual IEnumerable GetChildren(User user, bool includeLinkedChildren, string indexBy = null)
{
if (user == null)
{
@@ -889,7 +903,7 @@ namespace MediaBrowser.Controller.Entities
}
//the true root should return our users root folder children
- if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, indexBy);
+ if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, includeLinkedChildren, indexBy);
IEnumerable result = null;
@@ -898,24 +912,37 @@ namespace MediaBrowser.Controller.Entities
result = GetIndexedChildren(user, indexBy);
}
+ if (result != null)
+ {
+ return result;
+ }
+
+ var children = Children;
+
+ if (includeLinkedChildren)
+ {
+ children = children.Concat(GetLinkedChildren());
+ }
+
// If indexed is false or the indexing function is null
- return result ?? (Children.Where(c => c.IsVisible(user)));
+ return children.Where(c => c.IsVisible(user));
}
///
/// Gets allowed recursive children of an item
///
/// The user.
+ /// if set to true [include linked children].
/// IEnumerable{BaseItem}.
///
- public IEnumerable GetRecursiveChildren(User user)
+ public IEnumerable GetRecursiveChildren(User user, bool includeLinkedChildren = false)
{
if (user == null)
{
throw new ArgumentNullException();
}
- foreach (var item in GetChildren(user))
+ foreach (var item in GetChildren(user, includeLinkedChildren))
{
yield return item;
@@ -923,7 +950,7 @@ namespace MediaBrowser.Controller.Entities
if (subFolder != null)
{
- foreach (var subitem in subFolder.GetRecursiveChildren(user))
+ foreach (var subitem in subFolder.GetRecursiveChildren(user, includeLinkedChildren))
{
yield return subitem;
}
@@ -931,6 +958,81 @@ namespace MediaBrowser.Controller.Entities
}
}
+ ///
+ /// Gets the linked children.
+ ///
+ /// IEnumerable{BaseItem}.
+ public IEnumerable GetLinkedChildren()
+ {
+ return LinkedChildren
+ .Select(i => LibraryManager.RootFolder.FindByPath(i.Path))
+ .Where(i => i != null);
+ }
+
+ public override async Task RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
+ {
+ var changed = await base.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs).ConfigureAwait(false);
+
+ return changed || (SupportsLinkedChildren && RefreshLinkedChildren());
+ }
+
+ ///
+ /// Refreshes the linked children.
+ ///
+ /// true if XXXX, false otherwise
+ private bool RefreshLinkedChildren()
+ {
+ ItemResolveArgs resolveArgs;
+
+ try
+ {
+ resolveArgs = ResolveArgs;
+
+ if (!resolveArgs.IsDirectory)
+ {
+ return false;
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path);
+ return false;
+ }
+
+ var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
+ var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
+
+ var newShortcutLinks = resolveArgs.FileSystemChildren
+ .Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && FileSystem.IsShortcut(i.FullName))
+ .Select(i =>
+ {
+ try
+ {
+ return new LinkedChild
+ {
+ Path = FileSystem.ResolveShortcut(i.FullName),
+ Type = LinkedChildType.Shortcut
+ };
+ }
+ catch (IOException ex)
+ {
+ Logger.ErrorException("Error resolving shortcut {0}", ex, i.FullName);
+ return null;
+ }
+ })
+ .Where(i => i != null)
+ .ToList();
+
+ if (!newShortcutLinks.SequenceEqual(currentShortcutLinks))
+ {
+ newShortcutLinks.AddRange(currentManualLinks);
+ LinkedChildren = newShortcutLinks;
+ return true;
+ }
+
+ return false;
+ }
+
///
/// Folders need to validate and refresh
///
@@ -954,7 +1056,7 @@ namespace MediaBrowser.Controller.Entities
public override async Task SetPlayedStatus(User user, bool wasPlayed, IUserDataRepository userManager)
{
// Sweep through recursively and update status
- var tasks = GetRecursiveChildren(user).Where(i => !i.IsFolder).Select(c => c.SetPlayedStatus(user, wasPlayed, userManager));
+ var tasks = GetRecursiveChildren(user, true).Where(i => !i.IsFolder).Select(c => c.SetPlayedStatus(user, wasPlayed, userManager));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs
new file mode 100644
index 0000000000..edc5a7ac88
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/LinkedChild.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+
+namespace MediaBrowser.Controller.Entities
+{
+ public class LinkedChild
+ {
+ public string Path { get; set; }
+ public LinkedChildType Type { get; set; }
+ }
+
+ public enum LinkedChildType
+ {
+ Manual = 1,
+ Shortcut = 2
+ }
+
+ public class LinkedChildComparer : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ var a = (LinkedChild)x;
+
+ var b = (LinkedChild)y;
+
+ if (!string.Equals(a.Path, b.Path, StringComparison.OrdinalIgnoreCase))
+ {
+ return string.Compare(a.Path, b.Path, StringComparison.OrdinalIgnoreCase);
+ }
+ if (a.Type != b.Type)
+ {
+ return a.Type.CompareTo(b.Type);
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 34f09b4b09..2ee3ccffe9 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -6,6 +6,12 @@ namespace MediaBrowser.Controller.Entities.Movies
///
public class BoxSet : Folder
{
-
+ protected override bool SupportsLinkedChildren
+ {
+ get
+ {
+ return true;
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 502c7a7b82..6910722d68 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -78,6 +78,7 @@
+
diff --git a/MediaBrowser.Model/Dto/ImageOptions.cs b/MediaBrowser.Model/Dto/ImageOptions.cs
index 80614831a2..63c0f70abe 100644
--- a/MediaBrowser.Model/Dto/ImageOptions.cs
+++ b/MediaBrowser.Model/Dto/ImageOptions.cs
@@ -72,6 +72,7 @@ namespace MediaBrowser.Model.Dto
public ImageOptions()
{
Quality = 100;
+ EnableImageEnhancers = true;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index 71d0144684..02ecb4fca8 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -229,7 +229,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
{
var user = _userManager.GetUserById(userId);
- var collections = user.RootFolder.GetChildren(user).ToList();
+ var collections = user.RootFolder.GetChildren(user, true).ToList();
var allRecursiveChildren = user.RootFolder.GetRecursiveChildren(user).ToDictionary(i => i.Id);
diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs
index 5ed2537637..db923e5e21 100644
--- a/MediaBrowser.ServerApplication/App.xaml.cs
+++ b/MediaBrowser.ServerApplication/App.xaml.cs
@@ -255,7 +255,14 @@ namespace MediaBrowser.ServerApplication
process.Exited += ProcessExited;
- process.Start();
+ try
+ {
+ process.Start();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("There was an error launching your web browser. Please check your defualt browser settings.");
+ }
}
///
diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
index 577ac93bbb..6dabd85af2 100644
--- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
+++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
@@ -90,7 +90,7 @@ namespace MediaBrowser.ServerApplication
Cursor = Cursors.Wait;
await Task.Run(() =>
{
- IEnumerable children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children : _libraryManager.RootFolder.GetChildren(CurrentUser);
+ IEnumerable children = CurrentUser.Name == "Physical" ? _libraryManager.RootFolder.Children : _libraryManager.RootFolder.GetChildren(CurrentUser, true);
children = OrderByName(children, CurrentUser);
foreach (Folder folder in children)
@@ -102,7 +102,7 @@ namespace MediaBrowser.ServerApplication
var prefs = ddlProfile.SelectedItem != null ? _displayPreferencesManager.GetDisplayPreferences(currentFolder.GetDisplayPreferencesId((ddlProfile.SelectedItem as User).Id)) ?? new DisplayPreferences { SortBy = ItemSortBy.SortName } : new DisplayPreferences { SortBy = ItemSortBy.SortName };
var node = new TreeViewItem { Tag = currentFolder };
- var subChildren = currentFolder.GetChildren(CurrentUser, prefs.IndexBy);
+ var subChildren = currentFolder.GetChildren(CurrentUser, true, prefs.IndexBy);
subChildren = OrderByName(subChildren, CurrentUser);
AddChildren(node, subChildren, CurrentUser);
node.Header = currentFolder.Name + " (" +
@@ -153,8 +153,8 @@ namespace MediaBrowser.ServerApplication
if (subFolder != null)
{
var prefs = _displayPreferencesManager.GetDisplayPreferences(subFolder.GetDisplayPreferencesId(user.Id));
-
- AddChildren(node, OrderBy(subFolder.GetChildren(user), user, prefs.SortBy), user);
+
+ AddChildren(node, OrderBy(subFolder.GetChildren(user, true), user, prefs.SortBy), user);
node.Header = item.Name + " (" + node.Items.Count + ")";
}
else
@@ -374,7 +374,7 @@ namespace MediaBrowser.ServerApplication
//re-build the current item's children as an index
prefs.IndexBy = ddlIndexBy.SelectedItem as string;
treeItem.Items.Clear();
- AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy), CurrentUser);
+ AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, true, prefs.IndexBy), CurrentUser, prefs.SortBy), CurrentUser);
treeItem.Header = folder.Name + "(" +
treeItem.Items.Count + ")";
Cursor = Cursors.Arrow;
@@ -415,7 +415,7 @@ namespace MediaBrowser.ServerApplication
//re-sort
prefs.SortBy = ddlSortBy.SelectedItem as string;
treeItem.Items.Clear();
- AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, prefs.IndexBy), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser);
+ AddChildren(treeItem, OrderBy(folder.GetChildren(CurrentUser, true, prefs.IndexBy), CurrentUser, prefs.SortBy ?? ItemSortBy.SortName), CurrentUser);
treeItem.Header = folder.Name + "(" +
treeItem.Items.Count + ")";
Cursor = Cursors.Arrow;