fixes #1001 - Support downloading

pull/702/head
Luke Pulverenti 10 years ago
parent 4ae6b5f675
commit b6d59c7688

@ -226,6 +226,18 @@ namespace MediaBrowser.Api.Library
public string TvdbId { get; set; } 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> /// <summary>
/// Class LibraryService /// Class LibraryService
/// </summary> /// </summary>
@ -289,6 +301,28 @@ namespace MediaBrowser.Api.Library
Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None)); 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) public object Get(GetFile request)
{ {
var item = _libraryManager.GetItemById(request.Id); var item = _libraryManager.GetItemById(request.Id);
@ -458,23 +492,9 @@ namespace MediaBrowser.Api.Library
var auth = _authContext.GetAuthorizationInfo(Request); var auth = _authContext.GetAuthorizationInfo(Request);
var user = _userManager.GetUserById(auth.UserId); 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();
{
throw new UnauthorizedAccessException();
}
}
else
{
if (!user.Policy.EnableContentDeletion)
{
throw new UnauthorizedAccessException();
}
} }
var task = _libraryManager.DeleteItem(item); var task = _libraryManager.DeleteItem(item);

@ -323,13 +323,13 @@ namespace MediaBrowser.Api.Playback
switch (qualitySetting) switch (qualitySetting)
{ {
case EncodingQuality.HighSpeed: case EncodingQuality.HighSpeed:
param += " -crf 23"; param += " -subq 0 -crf 23";
break; break;
case EncodingQuality.HighQuality: case EncodingQuality.HighQuality:
param += " -crf 20"; param += " -subq 3 -crf 20";
break; break;
case EncodingQuality.MaxQuality: case EncodingQuality.MaxQuality:
param += " -crf 18"; param += " -subq 6 -crf 18";
break; break;
} }
} }
@ -507,7 +507,7 @@ namespace MediaBrowser.Api.Playback
} }
} }
return param; return "-pix_fmt yuv420p " + param;
} }
protected string GetAudioFilterParam(StreamState state, bool isHls) protected string GetAudioFilterParam(StreamState state, bool isHls)

@ -97,6 +97,7 @@ namespace MediaBrowser.Api.Playback.Progressive
if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase)) 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"; format = " -f mp4 -movflags frag_keyframe+empty_moov";
} }

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

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

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

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

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

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

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

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

@ -239,6 +239,38 @@ namespace MediaBrowser.Controller.Entities
get { return this.GetImagePath(ImageType.Primary); } 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> /// <summary>
/// Gets or sets the date created. /// Gets or sets the date created.
/// </summary> /// </summary>

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

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

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

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

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

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

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

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

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

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

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

@ -64,6 +64,19 @@ namespace MediaBrowser.Controller.Entities
LinkedAlternateVersions = new List<LinkedChild>(); 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] [IgnoreDataMember]
public override bool SupportsAddingToPlaylist public override bool SupportsAddingToPlaylist
{ {

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

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

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

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

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

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

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

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

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

@ -99,6 +99,12 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The path.</value> /// <value>The path.</value>
public string Path { get; set; } 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> /// <summary>
/// Overview of the recording. /// Overview of the recording.
/// </summary> /// </summary>

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

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

@ -284,6 +284,20 @@ namespace MediaBrowser.Server.Implementations.Dto
AttachLinkedChildImages(dto, playlist, user, options); 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; return dto;
} }

@ -74,7 +74,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
ValidateUserAccess(user, request, authAttribtues, auth); 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(); var roles = authAttribtues.GetRoles().ToList();
@ -142,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
StringComparer.OrdinalIgnoreCase); StringComparer.OrdinalIgnoreCase);
} }
private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo)
{ {
if (!_config.Configuration.IsStartupWizardCompleted && if (!_config.Configuration.IsStartupWizardCompleted &&
authAttribtues.AllowBeforeStartupWizard) authAttribtues.AllowBeforeStartupWizard)
@ -150,6 +152,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
return true; return true;
} }
if (string.IsNullOrWhiteSpace(auth.Token))
{
return true;
}
if (tokenInfo != null && string.IsNullOrWhiteSpace(tokenInfo.UserId))
{
return true;
}
return false; 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) private bool IsValidConnectKey(string token)

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

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

@ -285,10 +285,10 @@
"ButtonHelp": "Help", "ButtonHelp": "Help",
"OptionAllowUserToManageServer": "Allow this user to manage the server", "OptionAllowUserToManageServer": "Allow this user to manage the server",
"HeaderFeatureAccess": "Feature Access", "HeaderFeatureAccess": "Feature Access",
"OptionAllowMediaPlayback": "Allow media playback", "OptionAllowMediaPlayback": "Media playback",
"OptionAllowBrowsingLiveTv": "Allow browsing of live tv", "OptionAllowBrowsingLiveTv": "Live TV",
"OptionAllowDeleteLibraryContent": "Allow deletion of library content", "OptionAllowDeleteLibraryContent": "Media deletion",
"OptionAllowManageLiveTv": "Allow management of live tv recordings", "OptionAllowManageLiveTv": "Live TV recording management",
"OptionAllowRemoteControlOthers": "Allow remote control of other users", "OptionAllowRemoteControlOthers": "Allow remote control of other users",
"OptionAllowRemoteSharedDevices": "Allow remote control of shared devices", "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
"OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.", "OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
@ -1133,7 +1133,7 @@
"ViewTypeLiveTvRecordingGroups": "Recordings", "ViewTypeLiveTvRecordingGroups": "Recordings",
"ViewTypeLiveTvChannels": "Channels", "ViewTypeLiveTvChannels": "Channels",
"LabelEasyPinCode": "Easy pin code:", "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", "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.", "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", "HeaderPassword": "Password",
@ -1362,7 +1362,8 @@
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.", "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
"TabActivity": "Activity", "TabActivity": "Activity",
"TitleSync": "Sync", "TitleSync": "Sync",
"OptionAllowSyncContent": "Allow syncing media to devices", "OptionAllowSyncContent": "Sync",
"OptionAllowContentDownloading": "Media downloading",
"NameSeasonUnknown": "Season Unknown", "NameSeasonUnknown": "Season Unknown",
"NameSeasonNumber": "Season {0}", "NameSeasonNumber": "Season {0}",
"LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)", "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)",

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

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

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

Loading…
Cancel
Save