fixes #1001 - Support downloading

This commit is contained in:
Luke Pulverenti 2015-02-06 00:39:07 -05:00
parent 4ae6b5f675
commit b6d59c7688
44 changed files with 322 additions and 66 deletions

View File

@ -226,6 +226,18 @@ namespace MediaBrowser.Api.Library
public string TvdbId { get; set; }
}
[Route("/Items/{Id}/Download", "GET", Summary = "Downloads item media")]
[Authenticated(Roles = "download")]
public class GetDownload
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
}
/// <summary>
/// Class LibraryService
/// </summary>
@ -273,7 +285,7 @@ namespace MediaBrowser.Api.Library
}
var dtoOptions = GetDtoOptions(request);
var result = new ItemsResult
{
TotalRecordCount = items.Count,
@ -289,6 +301,28 @@ namespace MediaBrowser.Api.Library
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None));
}
public object Get(GetDownload request)
{
var item = _libraryManager.GetItemById(request.Id);
if (!item.CanDelete())
{
throw new ArgumentException("Item does not support downloading");
}
var headers = new Dictionary<string, string>();
// Quotes are valid in linux. They'll possibly cause issues here
var filename = Path.GetFileName(item.Path).Replace("\"", string.Empty);
headers["Content-Disposition"] = string.Format("inline; filename=\"{0}\"", filename);
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
Path = item.Path,
ResponseHeaders = headers
});
}
public object Get(GetFile request)
{
var item = _libraryManager.GetItemById(request.Id);
@ -347,7 +381,7 @@ namespace MediaBrowser.Api.Library
var dtoOptions = GetDtoOptions(request);
BaseItem parent = item.Parent;
while (parent != null)
{
if (user != null)
@ -458,23 +492,9 @@ namespace MediaBrowser.Api.Library
var auth = _authContext.GetAuthorizationInfo(Request);
var user = _userManager.GetUserById(auth.UserId);
if (item is Playlist || item is BoxSet)
if (!item.CanDelete(user))
{
// For now this is allowed if user can see the playlist
}
else if (item is ILiveTvRecording)
{
if (!user.Policy.EnableLiveTvManagement)
{
throw new UnauthorizedAccessException();
}
}
else
{
if (!user.Policy.EnableContentDeletion)
{
throw new UnauthorizedAccessException();
}
throw new UnauthorizedAccessException();
}
var task = _libraryManager.DeleteItem(item);

View File

@ -123,7 +123,7 @@ namespace MediaBrowser.Api.Playback
private string GetOutputFilePath(StreamState state)
{
var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
var outputFileExtension = GetOutputFileExtension(state);
var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
@ -323,13 +323,13 @@ namespace MediaBrowser.Api.Playback
switch (qualitySetting)
{
case EncodingQuality.HighSpeed:
param += " -crf 23";
param += " -subq 0 -crf 23";
break;
case EncodingQuality.HighQuality:
param += " -crf 20";
param += " -subq 3 -crf 20";
break;
case EncodingQuality.MaxQuality:
param += " -crf 18";
param += " -subq 6 -crf 18";
break;
}
}
@ -507,7 +507,7 @@ namespace MediaBrowser.Api.Playback
}
}
return param;
return "-pix_fmt yuv420p " + param;
}
protected string GetAudioFilterParam(StreamState state, bool isHls)
@ -918,7 +918,7 @@ namespace MediaBrowser.Api.Playback
if (SupportsThrottleWithStream)
{
var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
url += "&transcodingJobId=" + transcodingJobId;
return string.Format("\"{0}\"", url);

View File

@ -97,6 +97,7 @@ namespace MediaBrowser.Api.Playback.Progressive
if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase))
{
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
format = " -f mp4 -movflags frag_keyframe+empty_moov";
}

View File

@ -67,5 +67,10 @@ namespace MediaBrowser.Controller.Channels
{
return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata");
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -3,10 +3,10 @@ using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@ -89,5 +89,10 @@ namespace MediaBrowser.Controller.Channels
return list;
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -1,11 +1,10 @@
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Users;
using System;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@ -76,5 +75,10 @@ namespace MediaBrowser.Controller.Channels
{
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -4,11 +4,11 @@ using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Channels
{
@ -119,5 +119,10 @@ namespace MediaBrowser.Controller.Channels
{
return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N"));
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -32,6 +32,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// The _virtual children
/// </summary>

View File

@ -113,6 +113,13 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
public override bool CanDownload()
{
var locationType = LocationType;
return locationType != LocationType.Remote &&
locationType != LocationType.Virtual;
}
/// <summary>
/// Gets or sets the artist.
/// </summary>

View File

@ -1,14 +1,13 @@
using System.Runtime.Serialization;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Audio
{
@ -35,6 +34,11 @@ namespace MediaBrowser.Controller.Entities.Audio
get { return true; }
}
public override bool CanDelete()
{
return !IsAccessedByName;
}
protected override IEnumerable<BaseItem> ActualChildren
{
get

View File

@ -39,6 +39,11 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>

View File

@ -239,6 +239,38 @@ namespace MediaBrowser.Controller.Entities
get { return this.GetImagePath(ImageType.Primary); }
}
public virtual bool CanDelete()
{
var locationType = LocationType;
return locationType != LocationType.Remote &&
locationType != LocationType.Virtual;
}
public virtual bool IsAuthorizedToDelete(User user)
{
return user.Policy.EnableContentDeletion;
}
public bool CanDelete(User user)
{
return CanDelete() && IsAuthorizedToDelete(user);
}
public virtual bool CanDownload()
{
return false;
}
public virtual bool IsAuthorizedToDownload(User user)
{
return user.Policy.EnableContentDownloading;
}
public bool CanDownload(User user)
{
return CanDownload() && IsAuthorizedToDownload(user);
}
/// <summary>
/// Gets or sets the date created.
/// </summary>

View File

@ -11,5 +11,10 @@ namespace MediaBrowser.Controller.Entities
{
get { return null; }
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -2,6 +2,7 @@
using MediaBrowser.Model.Configuration;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
@ -37,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
Tags = new List<string>();
}
public override bool CanDownload()
{
var locationType = LocationType;
return locationType != LocationType.Remote &&
locationType != LocationType.Virtual;
}
protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Book);

View File

@ -35,6 +35,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
public string CollectionType { get; set; }
/// <summary>

View File

@ -1,10 +1,10 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
{
@ -38,6 +38,13 @@ namespace MediaBrowser.Controller.Entities
public List<Guid> LocalTrailerIds { get; set; }
public List<Guid> RemoteTrailerIds { get; set; }
public override bool CanDownload()
{
var locationType = LocationType;
return locationType != LocationType.Remote &&
locationType != LocationType.Virtual;
}
/// <summary>
/// Gets or sets the tags.
/// </summary>

View File

@ -43,6 +43,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
{
return inputItems.Where(GetItemFilter());

View File

@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>

View File

@ -15,6 +15,10 @@ namespace MediaBrowser.Controller.Entities
/// <returns>IEnumerable{BaseItem}.</returns>
IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems);
/// <summary>
/// Gets the item filter.
/// </summary>
/// <returns>Func&lt;BaseItem, System.Boolean&gt;.</returns>
Func<BaseItem, bool> GetItemFilter();
}

View File

@ -74,6 +74,11 @@ namespace MediaBrowser.Controller.Entities.Movies
}
}
public override bool IsAuthorizedToDelete(User user)
{
return true;
}
/// <summary>
/// Gets the trailer ids.
/// </summary>

View File

@ -45,6 +45,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>

View File

@ -40,6 +40,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>

View File

@ -40,6 +40,11 @@ namespace MediaBrowser.Controller.Entities
return result.Items;
}
public override bool CanDelete()
{
return false;
}
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
{
var result = GetItems(new InternalItemsQuery

View File

@ -64,6 +64,19 @@ namespace MediaBrowser.Controller.Entities
LinkedAlternateVersions = new List<LinkedChild>();
}
public override bool CanDownload()
{
if (VideoType == VideoType.HdDvd || VideoType == VideoType.Dvd ||
VideoType == VideoType.BluRay)
{
return false;
}
var locationType = LocationType;
return locationType != LocationType.Remote &&
locationType != LocationType.Virtual;
}
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{

View File

@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override bool CanDelete()
{
return false;
}
/// <summary>
/// Gets a value indicating whether this instance is owned item.
/// </summary>

View File

@ -25,5 +25,9 @@ namespace MediaBrowser.Controller.LiveTv
Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken);
PlayAccess GetPlayAccess(User user);
bool CanDelete();
bool CanDelete(User user);
}
}

View File

@ -1,4 +1,5 @@
using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@ -93,5 +94,10 @@ namespace MediaBrowser.Controller.LiveTv
{
return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
}
public override bool IsAuthorizedToDelete(User user)
{
return user.Policy.EnableLiveTvManagement;
}
}
}

View File

@ -1,5 +1,4 @@
using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@ -8,6 +7,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Users;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@ -135,5 +135,10 @@ namespace MediaBrowser.Controller.LiveTv
{
return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -1,13 +1,13 @@
using System.Runtime.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Users;
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.LiveTv
{
@ -215,5 +215,10 @@ namespace MediaBrowser.Controller.LiveTv
{
return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
}
public override bool CanDelete()
{
return false;
}
}
}

View File

@ -92,5 +92,10 @@ namespace MediaBrowser.Controller.LiveTv
{
return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
}
public override bool IsAuthorizedToDelete(User user)
{
return user.Policy.EnableLiveTvManagement;
}
}
}

View File

@ -1,7 +1,5 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using System;
@ -40,6 +38,11 @@ namespace MediaBrowser.Controller.Playlists
}
}
public override bool IsAuthorizedToDelete(User user)
{
return true;
}
public override bool IsSaveLocalMetadataEnabled()
{
return true;

View File

@ -631,13 +631,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
switch (qualitySetting)
{
case EncodingQuality.HighSpeed:
param += " -crf 23";
param += " -subq 0 -crf 23";
break;
case EncodingQuality.HighQuality:
param += " -crf 20";
param += " -subq 3 -crf 20";
break;
case EncodingQuality.MaxQuality:
param += " -crf 18";
param += " -subq 6 -crf 18";
break;
}
}
@ -740,7 +740,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
param += " -level " + state.Options.Level.Value.ToString(UsCulture);
}
return param;
return "-pix_fmt yuv420p " + param;
}
protected string GetVideoBitrateParam(EncodingJob state, string videoCodec, bool isHls)

View File

@ -56,6 +56,8 @@ namespace MediaBrowser.Model.Dto
public int? AirsBeforeEpisodeNumber { get; set; }
public int? AbsoluteEpisodeNumber { get; set; }
public bool? DisplaySpecialsWithSeasons { get; set; }
public bool? CanDelete { get; set; }
public bool? CanDownload { get; set; }
public string PreferredMetadataLanguage { get; set; }
public string PreferredMetadataCountryCode { get; set; }

View File

@ -99,6 +99,12 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The path.</value>
public string Path { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance can delete.
/// </summary>
/// <value><c>null</c> if [can delete] contains no value, <c>true</c> if [can delete]; otherwise, <c>false</c>.</value>
public bool? CanDelete { get; set; }
/// <summary>
/// Overview of the recording.
/// </summary>

View File

@ -1,5 +1,4 @@

namespace MediaBrowser.Model.Querying
namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Used to control the data that gets attached to DtoBaseItems
@ -26,6 +25,16 @@ namespace MediaBrowser.Model.Querying
/// </summary>
Budget,
/// <summary>
/// The can delete
/// </summary>
CanDelete,
/// <summary>
/// The can download
/// </summary>
CanDownload,
/// <summary>
/// The chapters
/// </summary>

View File

@ -42,7 +42,8 @@ namespace MediaBrowser.Model.Users
public bool EnableMediaPlayback { get; set; }
public bool EnableContentDeletion { get; set; }
public bool EnableContentDownloading { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [enable synchronize].
/// </summary>
@ -80,6 +81,8 @@ namespace MediaBrowser.Model.Users
EnabledDevices = new string[] { };
EnableAllDevices = true;
EnableContentDownloading = true;
}
}
}

View File

@ -284,6 +284,20 @@ namespace MediaBrowser.Server.Implementations.Dto
AttachLinkedChildImages(dto, playlist, user, options);
}
if (fields.Contains(ItemFields.CanDelete))
{
dto.CanDelete = user == null
? item.CanDelete()
: item.CanDelete(user);
}
if (fields.Contains(ItemFields.CanDownload))
{
dto.CanDownload = user == null
? item.CanDownload()
: item.CanDownload(user);
}
return dto;
}

View File

@ -74,7 +74,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
ValidateUserAccess(user, request, authAttribtues, auth);
}
if (!IsExemptFromRoles(auth, authAttribtues))
var info = (AuthenticationInfo)request.Items["OriginalAuthenticationInfo"];
if (!IsExemptFromRoles(auth, authAttribtues, info))
{
var roles = authAttribtues.GetRoles().ToList();
@ -142,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
StringComparer.OrdinalIgnoreCase);
}
private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues)
private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo)
{
if (!_config.Configuration.IsStartupWizardCompleted &&
authAttribtues.AllowBeforeStartupWizard)
@ -150,6 +152,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
return true;
}
if (string.IsNullOrWhiteSpace(auth.Token))
{
return true;
}
if (tokenInfo != null && string.IsNullOrWhiteSpace(tokenInfo.UserId))
{
return true;
}
return false;
}
@ -175,6 +187,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
};
}
}
if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
{
if (user == null || !user.Policy.EnableContentDownloading)
{
throw new SecurityException("User does not have download access.")
{
SecurityExceptionType = SecurityExceptionType.Unauthenticated
};
}
}
}
private bool IsValidConnectKey(string token)

View File

@ -229,6 +229,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
ServerId = _appHost.SystemId
};
dto.CanDelete = user == null
? recording.CanDelete()
: recording.CanDelete(user);
dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
if (info.Status == RecordingStatus.InProgress)

View File

@ -48,6 +48,7 @@
"LabelFailed": "(failed)",
"ButtonHelp": "Help",
"ButtonSave": "Save",
"ButtonDownload": "Download",
"SyncJobStatusQueued": "Queued",
"SyncJobStatusConverting": "Converting",
"SyncJobStatusFailed": "Failed",
@ -56,6 +57,7 @@
"SyncJobStatusReadyToTransfer": "Ready to Transfer",
"SyncJobStatusTransferring": "Transferring",
"SyncJobStatusCompletedWithError": "Synced with errors",
"SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
"LabelCollection": "Collection",
"HeaderAddToCollection": "Add to Collection",
"NewCollectionNameExample": "Example: Star Wars Collection",

View File

@ -285,10 +285,10 @@
"ButtonHelp": "Help",
"OptionAllowUserToManageServer": "Allow this user to manage the server",
"HeaderFeatureAccess": "Feature Access",
"OptionAllowMediaPlayback": "Allow media playback",
"OptionAllowBrowsingLiveTv": "Allow browsing of live tv",
"OptionAllowDeleteLibraryContent": "Allow deletion of library content",
"OptionAllowManageLiveTv": "Allow management of live tv recordings",
"OptionAllowMediaPlayback": "Media playback",
"OptionAllowBrowsingLiveTv": "Live TV",
"OptionAllowDeleteLibraryContent": "Media deletion",
"OptionAllowManageLiveTv": "Live TV recording management",
"OptionAllowRemoteControlOthers": "Allow remote control of other users",
"OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
"OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
@ -1133,7 +1133,7 @@
"ViewTypeLiveTvRecordingGroups": "Recordings",
"ViewTypeLiveTvChannels": "Channels",
"LabelEasyPinCode": "Easy pin code:",
"EasyPasswordHelp": "Your easy pin code is used for offline access with supported Media Browser apps, and can also be used for easy in-network sign in.",
"EasyPasswordHelp": "Your easy pin code is used for offline access with supported Media Browser apps, and can also be used for easy in-network sign in.",
"LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code",
"LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Media Browser apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.",
"HeaderPassword": "Password",
@ -1362,7 +1362,8 @@
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity",
"TitleSync": "Sync",
"OptionAllowSyncContent": "Allow syncing media to devices",
"OptionAllowSyncContent": "Sync",
"OptionAllowContentDownloading": "Media downloading",
"NameSeasonUnknown": "Season Unknown",
"NameSeasonNumber": "Season {0}",
"LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)",

View File

@ -311,8 +311,10 @@ namespace MediaBrowser.Server.Implementations.Sync
var itemByName = item as IItemByName;
if (itemByName != null)
{
var itemByNameFilter = itemByName.GetItemFilter();
return user.RootFolder
.GetRecursiveChildren(user, itemByName.GetItemFilter());
.GetRecursiveChildren(user, i => !i.IsFolder && itemByNameFilter(i));
}
if (item.IsFolder)

View File

@ -414,7 +414,6 @@ namespace MediaBrowser.WebDashboard.Api
"indexpage.js",
"itembynamedetailpage.js",
"itemdetailpage.js",
"itemgallery.js",
"itemlistpage.js",
"librarypathmapping.js",
"reports.js",

View File

@ -1656,9 +1656,6 @@
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="dashboard-ui\itemgallery.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\librarysettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -1707,9 +1704,6 @@
<Content Include="dashboard-ui\scripts\edititemmetadata.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\itemgallery.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\librarysettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>