commit
862bcdba67
|
@ -7,6 +7,7 @@
|
|||
- [anthonylavado](https://github.com/anthonylavado)
|
||||
- [Artiume](https://github.com/Artiume)
|
||||
- [AThomsen](https://github.com/AThomsen)
|
||||
- [barronpm](https://github.com/barronpm)
|
||||
- [bilde2910](https://github.com/bilde2910)
|
||||
- [bfayers](https://github.com/bfayers)
|
||||
- [BnMcG](https://github.com/BnMcG)
|
||||
|
@ -130,6 +131,7 @@
|
|||
- [XVicarious](https://github.com/XVicarious)
|
||||
- [YouKnowBlom](https://github.com/YouKnowBlom)
|
||||
- [KristupasSavickas](https://github.com/KristupasSavickas)
|
||||
- [Pusta](https://github.com/pusta)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
|
|
@ -4,11 +4,12 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Service;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.TV;
|
||||
|
@ -32,7 +33,8 @@ namespace Emby.Dlna.ContentDirectory
|
|||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
|
||||
public ContentDirectory(IDlnaManager dlna,
|
||||
public ContentDirectory(
|
||||
IDlnaManager dlna,
|
||||
IUserDataManager userDataManager,
|
||||
IImageProcessor imageProcessor,
|
||||
ILibraryManager libraryManager,
|
||||
|
@ -131,7 +133,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
foreach (var user in _userManager.Users)
|
||||
{
|
||||
if (user.Policy.IsAdministrator)
|
||||
if (user.HasPermission(PermissionKind.IsAdministrator))
|
||||
{
|
||||
return user;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System.Threading;
|
|||
using System.Xml;
|
||||
using Emby.Dlna.Didl;
|
||||
using Emby.Dlna.Service;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
|
@ -17,7 +18,6 @@ using MediaBrowser.Controller.Dto;
|
|||
using MediaBrowser.Controller.Entities;
|
||||
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;
|
||||
|
@ -28,6 +28,12 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Book = MediaBrowser.Controller.Entities.Book;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
|
||||
namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
|
@ -460,12 +466,12 @@ namespace Emby.Dlna.ContentDirectory
|
|||
}
|
||||
else if (search.SearchType == SearchType.Playlist)
|
||||
{
|
||||
//items = items.OfType<Playlist>();
|
||||
// items = items.OfType<Playlist>();
|
||||
isFolder = true;
|
||||
}
|
||||
else if (search.SearchType == SearchType.MusicAlbum)
|
||||
{
|
||||
//items = items.OfType<MusicAlbum>();
|
||||
// items = items.OfType<MusicAlbum>();
|
||||
isFolder = true;
|
||||
}
|
||||
|
||||
|
@ -731,7 +737,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
return GetGenres(item, user, query);
|
||||
}
|
||||
|
||||
var array = new ServerItem[]
|
||||
var array = new[]
|
||||
{
|
||||
new ServerItem(item)
|
||||
{
|
||||
|
@ -920,7 +926,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
private QueryResult<ServerItem> GetMovieCollections(User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Recursive = true;
|
||||
//query.Parent = parent;
|
||||
// query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
|
||||
|
@ -1115,7 +1121,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
private QueryResult<ServerItem> GetMusicPlaylists(User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Parent = null;
|
||||
query.IncludeItemTypes = new[] { typeof(Playlist).Name };
|
||||
query.IncludeItemTypes = new[] { nameof(Playlist) };
|
||||
query.SetUser(user);
|
||||
query.Recursive = true;
|
||||
|
||||
|
@ -1132,10 +1138,9 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
UserId = user.Id,
|
||||
Limit = 50,
|
||||
IncludeItemTypes = new[] { typeof(Audio).Name },
|
||||
ParentId = parent == null ? Guid.Empty : parent.Id,
|
||||
IncludeItemTypes = new[] { nameof(Audio) },
|
||||
ParentId = parent?.Id ?? Guid.Empty,
|
||||
GroupItems = true
|
||||
|
||||
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
|
||||
|
||||
return ToResult(items);
|
||||
|
@ -1150,7 +1155,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||
Limit = query.Limit,
|
||||
StartIndex = query.StartIndex,
|
||||
UserId = query.User.Id
|
||||
|
||||
}, new[] { parent }, query.DtoOptions);
|
||||
|
||||
return ToResult(result);
|
||||
|
@ -1167,7 +1171,6 @@ namespace Emby.Dlna.ContentDirectory
|
|||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
ParentId = parent == null ? Guid.Empty : parent.Id,
|
||||
GroupItems = false
|
||||
|
||||
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
|
||||
|
||||
return ToResult(items);
|
||||
|
@ -1177,14 +1180,14 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
var items = _userViewManager.GetLatestItems(
|
||||
new LatestItemsQuery
|
||||
{
|
||||
UserId = user.Id,
|
||||
Limit = 50,
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name },
|
||||
ParentId = parent == null ? Guid.Empty : parent.Id,
|
||||
IncludeItemTypes = new[] { nameof(Movie) },
|
||||
ParentId = parent?.Id ?? Guid.Empty,
|
||||
GroupItems = true
|
||||
|
||||
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
|
||||
|
||||
return ToResult(items);
|
||||
|
@ -1217,7 +1220,11 @@ namespace Emby.Dlna.ContentDirectory
|
|||
Recursive = true,
|
||||
ParentId = parentId,
|
||||
GenreIds = new[] { item.Id },
|
||||
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name },
|
||||
IncludeItemTypes = new[]
|
||||
{
|
||||
nameof(Movie),
|
||||
nameof(Series)
|
||||
},
|
||||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
DtoOptions = GetDtoOptions()
|
||||
|
|
|
@ -6,14 +6,13 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Emby.Dlna.Configuration;
|
||||
using Emby.Dlna.ContentDirectory;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
|
@ -23,6 +22,13 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
using XmlAttribute = MediaBrowser.Model.Dlna.XmlAttribute;
|
||||
|
||||
namespace Emby.Dlna.Didl
|
||||
{
|
||||
|
@ -92,21 +98,21 @@ namespace Emby.Dlna.Didl
|
|||
{
|
||||
using (var writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
// writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
// didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
|
||||
WriteXmlRootAttributes(_profile, writer);
|
||||
|
||||
WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo);
|
||||
|
||||
writer.WriteFullEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
// writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
|
@ -421,7 +427,6 @@ namespace Emby.Dlna.Didl
|
|||
case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
|
||||
case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
|
||||
case StubType.Series: return _localization.GetLocalizedString("Shows");
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +675,7 @@ namespace Emby.Dlna.Didl
|
|||
return;
|
||||
}
|
||||
|
||||
MediaBrowser.Model.Dlna.XmlAttribute secAttribute = null;
|
||||
XmlAttribute secAttribute = null;
|
||||
foreach (var attribute in _profile.XmlRootAttributes)
|
||||
{
|
||||
if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -706,7 +711,7 @@ namespace Emby.Dlna.Didl
|
|||
{
|
||||
// Don't filter on dc:title because not all devices will include it in the filter
|
||||
// MediaMonkey for example won't display content without a title
|
||||
//if (filter.Contains("dc:title"))
|
||||
// if (filter.Contains("dc:title"))
|
||||
{
|
||||
AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC);
|
||||
}
|
||||
|
@ -745,7 +750,7 @@ namespace Emby.Dlna.Didl
|
|||
AddValue(writer, "dc", "description", desc, NS_DC);
|
||||
}
|
||||
}
|
||||
//if (filter.Contains("upnp:longDescription"))
|
||||
// if (filter.Contains("upnp:longDescription"))
|
||||
//{
|
||||
// if (!string.IsNullOrWhiteSpace(item.Overview))
|
||||
// {
|
||||
|
@ -995,7 +1000,6 @@ namespace Emby.Dlna.Didl
|
|||
}
|
||||
|
||||
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
|
||||
|
||||
}
|
||||
|
||||
private void AddImageResElement(
|
||||
|
@ -1131,25 +1135,24 @@ namespace Emby.Dlna.Didl
|
|||
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
//_imageProcessor.GetImageSize(item, imageInfo);
|
||||
// _imageProcessor.GetImageSize(item, imageInfo);
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
|
||||
else if (width == -1 || height == -1)
|
||||
{
|
||||
width = null;
|
||||
height = null;
|
||||
}
|
||||
|
||||
//try
|
||||
// try
|
||||
//{
|
||||
// var size = _imageProcessor.GetImageSize(imageInfo);
|
||||
|
||||
// width = size.Width;
|
||||
// height = size.Height;
|
||||
//}
|
||||
//catch
|
||||
// catch
|
||||
//{
|
||||
|
||||
//}
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Emby.Dlna.Didl
|
|||
public Filter()
|
||||
: this("*")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Filter(string filter)
|
||||
|
@ -26,7 +25,7 @@ namespace Emby.Dlna.Didl
|
|||
{
|
||||
// Don't bother with this. Some clients (media monkey) use the filter and then don't display very well when very little data comes back.
|
||||
return true;
|
||||
//return _all || ListHelper.ContainsIgnoreCase(_fields, field);
|
||||
// return _all || ListHelper.ContainsIgnoreCase(_fields, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,6 @@ namespace Emby.Dlna
|
|||
.Select(i => i.Item2)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DeviceProfile GetDefaultProfile()
|
||||
|
@ -251,7 +250,7 @@ namespace Emby.Dlna
|
|||
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
|
||||
case HeaderMatchType.Substring:
|
||||
var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
|
||||
//_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
|
||||
// _logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
|
||||
return isMatch;
|
||||
case HeaderMatchType.Regex:
|
||||
return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
|
||||
|
@ -566,9 +565,9 @@ namespace Emby.Dlna
|
|||
new Foobar2000Profile(),
|
||||
new SharpSmartTvProfile(),
|
||||
new MediaMonkeyProfile(),
|
||||
//new Windows81Profile(),
|
||||
//new WindowsMediaCenterProfile(),
|
||||
//new WindowsPhoneProfile(),
|
||||
// new Windows81Profile(),
|
||||
// new WindowsMediaCenterProfile(),
|
||||
// new WindowsPhoneProfile(),
|
||||
new DirectTvProfile(),
|
||||
new DishHopperJoeyProfile(),
|
||||
new DefaultProfile(),
|
||||
|
|
|
@ -169,7 +169,6 @@ namespace Emby.Dlna.Eventing
|
|||
{
|
||||
using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
|
|
@ -276,7 +276,7 @@ namespace Emby.Dlna.Main
|
|||
|
||||
var device = new SsdpRootDevice
|
||||
{
|
||||
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
|
||||
CacheLifetime = TimeSpan.FromSeconds(1800), // How long SSDP clients can cache this info.
|
||||
Location = uri, // Must point to the URL that serves your devices UPnP description document.
|
||||
Address = address,
|
||||
SubnetMask = _networkManager.GetLocalIpSubnetMask(address),
|
||||
|
|
|
@ -750,7 +750,7 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
if (track == null)
|
||||
{
|
||||
//If track is null, some vendors do this, use GetMediaInfo instead
|
||||
// If track is null, some vendors do this, use GetMediaInfo instead
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
|
@ -794,7 +794,6 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// first try to add a root node with a dlna namesapce
|
||||
|
@ -806,7 +805,6 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// some devices send back invalid xml
|
||||
|
@ -816,7 +814,6 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Didl;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
|
@ -22,6 +23,7 @@ using MediaBrowser.Model.Globalization;
|
|||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Photo = MediaBrowser.Controller.Entities.Photo;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
|
@ -446,7 +448,13 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
}
|
||||
|
||||
private PlaylistItem CreatePlaylistItem(BaseItem item, User user, long startPostionTicks, string mediaSourceId, int? audioStreamIndex, int? subtitleStreamIndex)
|
||||
private PlaylistItem CreatePlaylistItem(
|
||||
BaseItem item,
|
||||
User user,
|
||||
long startPostionTicks,
|
||||
string mediaSourceId,
|
||||
int? audioStreamIndex,
|
||||
int? subtitleStreamIndex)
|
||||
{
|
||||
var deviceInfo = _device.Properties;
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Emby.Dlna.PlayTo
|
|||
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
|
||||
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
{
|
||||
//_logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
|
||||
// _logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,6 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -243,7 +242,6 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
_sessionLock.Dispose();
|
||||
|
|
|
@ -91,7 +91,6 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Emby.Dlna.Ssdp
|
|||
// (Optional) Set the filter so we only see notifications for devices we care about
|
||||
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
|
||||
// DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
|
||||
//_DeviceLocator.NotificationFilter = "upnp:rootdevice";
|
||||
// _DeviceLocator.NotificationFilter = "upnp:rootdevice";
|
||||
|
||||
// Connect our event handler so we process devices as they are found
|
||||
_deviceLocator.DeviceAvailable += OnDeviceLocatorDeviceAvailable;
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
|
@ -14,6 +15,7 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Photo = MediaBrowser.Controller.Entities.Photo;
|
||||
|
||||
namespace Emby.Drawing
|
||||
{
|
||||
|
@ -349,6 +351,13 @@ namespace Emby.Drawing
|
|||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetImageCacheTag(User user)
|
||||
{
|
||||
return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5()
|
||||
.ToString("N", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
|
||||
{
|
||||
var inputFormat = Path.GetExtension(originalImagePath)
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Notifications;
|
||||
|
@ -149,9 +150,7 @@ namespace Emby.Notifications.Api
|
|||
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
|
||||
public object Get(GetNotificationsSummary request)
|
||||
{
|
||||
return new NotificationsSummary
|
||||
{
|
||||
};
|
||||
return new NotificationsSummary();
|
||||
}
|
||||
|
||||
public Task Post(AddAdminNotification request)
|
||||
|
@ -164,7 +163,10 @@ namespace Emby.Notifications.Api
|
|||
Level = request.Level,
|
||||
Name = request.Name,
|
||||
Url = request.Url,
|
||||
UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToArray()
|
||||
UserIds = _userManager.Users
|
||||
.Where(user => user.HasPermission(PermissionKind.IsAdministrator))
|
||||
.Select(user => user.Id)
|
||||
.ToArray()
|
||||
};
|
||||
|
||||
return _notificationManager.SendNotification(notification, CancellationToken.None);
|
||||
|
|
|
@ -4,6 +4,8 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -101,7 +103,7 @@ namespace Emby.Notifications
|
|||
switch (request.SendToUserMode.Value)
|
||||
{
|
||||
case SendToUserType.Admins:
|
||||
return _userManager.Users.Where(i => i.Policy.IsAdministrator)
|
||||
return _userManager.Users.Where(i => i.HasPermission(PermissionKind.IsAdministrator))
|
||||
.Select(i => i.Id);
|
||||
case SendToUserType.All:
|
||||
return _userManager.UsersIds;
|
||||
|
@ -117,7 +119,7 @@ namespace Emby.Notifications
|
|||
var config = GetConfiguration();
|
||||
|
||||
return _userManager.Users
|
||||
.Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i.Policy))
|
||||
.Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i))
|
||||
.Select(i => i.Id);
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ namespace Emby.Notifications
|
|||
User = user
|
||||
};
|
||||
|
||||
_logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Name);
|
||||
_logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Username);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -88,25 +88,26 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
_subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure;
|
||||
|
||||
_userManager.UserCreated += OnUserCreated;
|
||||
_userManager.UserPasswordChanged += OnUserPasswordChanged;
|
||||
_userManager.UserDeleted += OnUserDeleted;
|
||||
_userManager.UserPolicyUpdated += OnUserPolicyUpdated;
|
||||
_userManager.UserLockedOut += OnUserLockedOut;
|
||||
_userManager.OnUserCreated += OnUserCreated;
|
||||
_userManager.OnUserPasswordChanged += OnUserPasswordChanged;
|
||||
_userManager.OnUserDeleted += OnUserDeleted;
|
||||
_userManager.OnUserLockedOut += OnUserLockedOut;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||
private async void OnUserLockedOut(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserLockedOutWithName"),
|
||||
e.Argument.Name),
|
||||
e.Argument.Username),
|
||||
NotificationType.UserLockedOut.ToString(),
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
e.Argument.Id)
|
||||
{
|
||||
LogSeverity = LogLevel.Error
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
|
||||
|
@ -152,7 +153,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"),
|
||||
user.Name,
|
||||
user.Username,
|
||||
GetItemName(item),
|
||||
e.DeviceName),
|
||||
GetPlaybackStoppedNotificationType(item.MediaType),
|
||||
|
@ -187,7 +188,7 @@ namespace Emby.Server.Implementations.Activity
|
|||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserStartedPlayingItemWithValues"),
|
||||
user.Name,
|
||||
user.Username,
|
||||
GetItemName(item),
|
||||
e.DeviceName),
|
||||
GetPlaybackNotificationType(item.MediaType),
|
||||
|
@ -304,49 +305,37 @@ namespace Emby.Server.Implementations.Activity
|
|||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserPolicyUpdated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserPolicyUpdatedWithName"),
|
||||
e.Argument.Name),
|
||||
"UserPolicyUpdated",
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserDeleted(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||
private async void OnUserDeleted(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserDeletedWithName"),
|
||||
e.Argument.Name),
|
||||
e.Argument.Username),
|
||||
"UserDeleted",
|
||||
Guid.Empty))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserPasswordChanged(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||
private async void OnUserPasswordChanged(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserPasswordChangedWithName"),
|
||||
e.Argument.Name),
|
||||
e.Argument.Username),
|
||||
"UserPasswordChanged",
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||
private async void OnUserCreated(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserCreatedWithName"),
|
||||
e.Argument.Name),
|
||||
e.Argument.Username),
|
||||
"UserCreated",
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
|
@ -510,11 +499,10 @@ namespace Emby.Server.Implementations.Activity
|
|||
|
||||
_subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure;
|
||||
|
||||
_userManager.UserCreated -= OnUserCreated;
|
||||
_userManager.UserPasswordChanged -= OnUserPasswordChanged;
|
||||
_userManager.UserDeleted -= OnUserDeleted;
|
||||
_userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
|
||||
_userManager.UserLockedOut -= OnUserLockedOut;
|
||||
_userManager.OnUserCreated -= OnUserCreated;
|
||||
_userManager.OnUserPasswordChanged -= OnUserPasswordChanged;
|
||||
_userManager.OnUserDeleted -= OnUserDeleted;
|
||||
_userManager.OnUserLockedOut -= OnUserLockedOut;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -562,11 +562,8 @@ namespace Emby.Server.Implementations
|
|||
|
||||
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
||||
|
||||
serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
|
||||
serviceCollection.AddSingleton<IUserManager, UserManager>();
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
// TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
|
||||
|
@ -659,15 +656,11 @@ namespace Emby.Server.Implementations
|
|||
|
||||
((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
|
||||
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
||||
((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
|
||||
|
||||
SetStaticProperties();
|
||||
|
||||
var userManager = (UserManager)Resolve<IUserManager>();
|
||||
userManager.Initialize();
|
||||
|
||||
var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
|
||||
((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
|
||||
((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, Resolve<IUserManager>());
|
||||
|
||||
FindParts();
|
||||
}
|
||||
|
@ -750,7 +743,6 @@ namespace Emby.Server.Implementations
|
|||
BaseItem.ProviderManager = Resolve<IProviderManager>();
|
||||
BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
|
||||
BaseItem.ItemRepository = Resolve<IItemRepository>();
|
||||
User.UserManager = Resolve<IUserManager>();
|
||||
BaseItem.FileSystem = _fileSystemManager;
|
||||
BaseItem.UserDataManager = Resolve<IUserDataManager>();
|
||||
BaseItem.ChannelManager = Resolve<IChannelManager>();
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
|
@ -13,8 +14,6 @@ using MediaBrowser.Controller.Configuration;
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
|
@ -24,6 +23,11 @@ using MediaBrowser.Model.IO;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
|
||||
namespace Emby.Server.Implementations.Channels
|
||||
{
|
||||
|
@ -791,7 +795,8 @@ namespace Emby.Server.Implementations.Channels
|
|||
return result;
|
||||
}
|
||||
|
||||
private async Task<ChannelItemResult> GetChannelItems(IChannel channel,
|
||||
private async Task<ChannelItemResult> GetChannelItems(
|
||||
IChannel channel,
|
||||
User user,
|
||||
string externalFolderId,
|
||||
ChannelItemSortField? sortField,
|
||||
|
@ -1067,7 +1072,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
}
|
||||
|
||||
// was used for status
|
||||
//if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal))
|
||||
// if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal))
|
||||
//{
|
||||
// item.ExternalEtag = info.Etag;
|
||||
// forceUpdate = true;
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
|
|
@ -162,7 +162,6 @@ namespace Emby.Server.Implementations.Data
|
|||
}
|
||||
|
||||
return false;
|
||||
|
||||
}, ReadTransactionMode);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ namespace Emby.Server.Implementations.Data
|
|||
_libraryManager.DeleteItem(item, new DeleteOptions
|
||||
{
|
||||
DeleteFileLocation = false
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -321,7 +321,6 @@ namespace Emby.Server.Implementations.Data
|
|||
AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames);
|
||||
AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames);
|
||||
AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames);
|
||||
|
||||
}, TransactionMode);
|
||||
|
||||
connection.RunQueries(postQueries);
|
||||
|
@ -2044,7 +2043,6 @@ namespace Emby.Server.Implementations.Data
|
|||
db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
|
||||
|
||||
InsertChapters(idBlob, chapters, db);
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -4360,7 +4358,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
// TODO this seems to be an idea for a better schema where ProviderIds are their own table
|
||||
// buut this is not implemented
|
||||
//hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
|
||||
// hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
|
||||
|
||||
// TODO this is a really BAD way to do it since the pair:
|
||||
// Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567
|
||||
|
@ -4789,7 +4787,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
connection.RunInTransaction(db =>
|
||||
{
|
||||
connection.ExecuteAll(sql);
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -5180,7 +5177,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LogQueryTime("GetItemValueNames", commandText, now);
|
||||
|
@ -5631,7 +5627,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
|
||||
|
||||
InsertPeople(itemIdBlob, people, db);
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -5788,7 +5783,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
|
||||
|
||||
InsertMediaStreams(itemIdBlob, streams, db);
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -6134,7 +6128,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
|
||||
|
||||
InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -346,7 +347,7 @@ namespace Emby.Server.Implementations.Data
|
|||
var userData = new UserItemData();
|
||||
|
||||
userData.Key = reader[0].ToString();
|
||||
//userData.UserId = reader[1].ReadGuidFromBlob();
|
||||
// userData.UserId = reader[1].ReadGuidFromBlob();
|
||||
|
||||
if (reader[2].SQLiteType != SQLiteType.Null)
|
||||
{
|
||||
|
|
|
@ -1,240 +0,0 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using MediaBrowser.Common.Json;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SQLitePCL.pretty;
|
||||
|
||||
namespace Emby.Server.Implementations.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SQLiteUserRepository
|
||||
/// </summary>
|
||||
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
|
||||
{
|
||||
private readonly JsonSerializerOptions _jsonOptions;
|
||||
|
||||
public SqliteUserRepository(
|
||||
ILogger<SqliteUserRepository> logger,
|
||||
IServerApplicationPaths appPaths)
|
||||
: base(logger)
|
||||
{
|
||||
_jsonOptions = JsonDefaults.GetOptions();
|
||||
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name => "SQLite";
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
var localUsersTableExists = TableExists(connection, "LocalUsersv2");
|
||||
|
||||
connection.RunQueries(new[] {
|
||||
"create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)",
|
||||
"drop index if exists idx_users"
|
||||
});
|
||||
|
||||
if (!localUsersTableExists && TableExists(connection, "Users"))
|
||||
{
|
||||
TryMigrateToLocalUsersTable(connection);
|
||||
}
|
||||
|
||||
RemoveEmptyPasswordHashes(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryMigrateToLocalUsersTable(ManagedConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.RunQueries(new[]
|
||||
{
|
||||
"INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error migrating users database");
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveEmptyPasswordHashes(ManagedConnection connection)
|
||||
{
|
||||
foreach (var user in RetrieveAllUsers(connection))
|
||||
{
|
||||
// If the user password is the sha1 hash of the empty string, remove it
|
||||
if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)
|
||||
&& !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
user.Password = null;
|
||||
var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
|
||||
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
|
||||
{
|
||||
statement.TryBind("@InternalId", user.InternalId);
|
||||
statement.TryBind("@data", serialized);
|
||||
statement.MoveNext();
|
||||
}
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a user in the repo
|
||||
/// </summary>
|
||||
public void CreateUser(User user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
|
||||
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
|
||||
{
|
||||
statement.TryBind("@guid", user.Id.ToByteArray());
|
||||
statement.TryBind("@data", serialized);
|
||||
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
var createdUser = GetUser(user.Id, connection);
|
||||
|
||||
if (createdUser == null)
|
||||
{
|
||||
throw new ApplicationException("created user should never be null");
|
||||
}
|
||||
|
||||
user.InternalId = createdUser.InternalId;
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateUser(User user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
|
||||
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
|
||||
{
|
||||
statement.TryBind("@InternalId", user.InternalId);
|
||||
statement.TryBind("@data", serialized);
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
||||
private User GetUser(Guid guid, ManagedConnection connection)
|
||||
{
|
||||
using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid"))
|
||||
{
|
||||
statement.TryBind("@guid", guid);
|
||||
|
||||
foreach (var row in statement.ExecuteQuery())
|
||||
{
|
||||
return GetUser(row);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private User GetUser(IReadOnlyList<IResultSetValue> row)
|
||||
{
|
||||
var id = row[0].ToInt64();
|
||||
var guid = row[1].ReadGuidFromBlob();
|
||||
|
||||
var user = JsonSerializer.Deserialize<User>(row[2].ToBlob(), _jsonOptions);
|
||||
user.InternalId = id;
|
||||
user.Id = guid;
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all users from the database
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{User}.</returns>
|
||||
public List<User> RetrieveAllUsers()
|
||||
{
|
||||
using (var connection = GetConnection(true))
|
||||
{
|
||||
return new List<User>(RetrieveAllUsers(connection));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all users from the database
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{User}.</returns>
|
||||
private IEnumerable<User> RetrieveAllUsers(ManagedConnection connection)
|
||||
{
|
||||
foreach (var row in connection.Query("select id,guid,data from LocalUsersv2"))
|
||||
{
|
||||
yield return GetUser(row);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">user</exception>
|
||||
public void DeleteUser(User user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
using (var connection = GetConnection())
|
||||
{
|
||||
connection.RunInTransaction(db =>
|
||||
{
|
||||
using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id"))
|
||||
{
|
||||
statement.TryBind("@id", user.InternalId);
|
||||
statement.MoveNext();
|
||||
}
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,11 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.Devices;
|
||||
|
@ -16,7 +17,6 @@ using MediaBrowser.Model.Events;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace Emby.Server.Implementations.Devices
|
||||
{
|
||||
|
@ -27,11 +27,10 @@ namespace Emby.Server.Implementations.Devices
|
|||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IAuthenticationRepository _authRepo;
|
||||
private readonly Dictionary<string, ClientCapabilities> _capabilitiesCache;
|
||||
private readonly object _capabilitiesSyncLock = new object();
|
||||
|
||||
public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||
|
||||
private readonly object _capabilitiesSyncLock = new object();
|
||||
|
||||
public DeviceManager(
|
||||
IAuthenticationRepository authRepo,
|
||||
IJsonSerializer json,
|
||||
|
@ -113,7 +112,7 @@ namespace Emby.Server.Implementations.Devices
|
|||
{
|
||||
IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
|
||||
{
|
||||
//UserId = query.UserId
|
||||
// UserId = query.UserId
|
||||
HasUser = true
|
||||
}).Items;
|
||||
|
||||
|
@ -175,7 +174,12 @@ namespace Emby.Server.Implementations.Devices
|
|||
throw new ArgumentNullException(nameof(deviceId));
|
||||
}
|
||||
|
||||
if (!CanAccessDevice(user.Policy, deviceId))
|
||||
if (user.HasPermission(PermissionKind.EnableAllDevices) || user.HasPermission(PermissionKind.IsAdministrator))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var capabilities = GetCapabilities(deviceId);
|
||||
|
||||
|
@ -187,20 +191,5 @@ namespace Emby.Server.Implementations.Devices
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CanAccessDevice(UserPolicy policy, string id)
|
||||
{
|
||||
if (policy.EnableAllDevices)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (policy.IsAdministrator)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return policy.EnabledDevices.Contains(id, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
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.Persistence;
|
||||
|
@ -24,6 +24,14 @@ using MediaBrowser.Model.Dto;
|
|||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Book = MediaBrowser.Controller.Entities.Book;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
using Person = MediaBrowser.Controller.Entities.Person;
|
||||
using Photo = MediaBrowser.Controller.Entities.Photo;
|
||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
|
||||
namespace Emby.Server.Implementations.Dto
|
||||
{
|
||||
|
@ -384,7 +392,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
if (options.ContainsField(ItemFields.ChildCount))
|
||||
{
|
||||
dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user);
|
||||
dto.ChildCount ??= GetChildCount(folder, user);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +406,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.DateLastMediaAdded = folder.DateLastMediaAdded;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (options.EnableUserData)
|
||||
|
@ -414,7 +421,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
if (options.ContainsField(ItemFields.BasicSyncInfo))
|
||||
{
|
||||
var userCanSync = user != null && user.Policy.EnableContentDownloading;
|
||||
var userCanSync = user != null && user.HasPermission(PermissionKind.EnableContentDownloading);
|
||||
if (userCanSync && item.SupportsExternalTransfer)
|
||||
{
|
||||
dto.SupportsSync = true;
|
||||
|
@ -586,7 +593,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
_logger.LogError(ex, "Error getting person {Name}", c);
|
||||
return null;
|
||||
}
|
||||
|
||||
}).Where(i => i != null)
|
||||
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(x => x.First())
|
||||
|
@ -939,7 +945,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
dto.AlbumPrimaryImageTag = GetTagAndFillBlurhash(dto, albumParent, ImageType.Primary);
|
||||
}
|
||||
|
||||
//if (options.ContainsField(ItemFields.MediaSourceCount))
|
||||
// if (options.ContainsField(ItemFields.MediaSourceCount))
|
||||
//{
|
||||
// Songs always have one
|
||||
//}
|
||||
|
@ -949,13 +955,13 @@ namespace Emby.Server.Implementations.Dto
|
|||
{
|
||||
dto.Artists = hasArtist.Artists;
|
||||
|
||||
//var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
|
||||
// var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
|
||||
//{
|
||||
// EnableTotalRecordCount = false,
|
||||
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
|
||||
//});
|
||||
|
||||
//dto.ArtistItems = artistItems.Items
|
||||
// dto.ArtistItems = artistItems.Items
|
||||
// .Select(i =>
|
||||
// {
|
||||
// var artist = i.Item1;
|
||||
|
@ -968,7 +974,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
// .ToList();
|
||||
|
||||
// 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();
|
||||
// var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
|
||||
dto.ArtistItems = hasArtist.Artists
|
||||
//.Except(foundArtists, new DistinctNameComparer())
|
||||
.Select(i =>
|
||||
|
@ -993,7 +999,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
|
||||
return null;
|
||||
|
||||
}).Where(i => i != null).ToArray();
|
||||
}
|
||||
|
||||
|
@ -1002,13 +1007,13 @@ namespace Emby.Server.Implementations.Dto
|
|||
{
|
||||
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
|
||||
|
||||
//var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
|
||||
// var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
|
||||
//{
|
||||
// EnableTotalRecordCount = false,
|
||||
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
|
||||
//});
|
||||
|
||||
//dto.AlbumArtists = artistItems.Items
|
||||
// dto.AlbumArtists = artistItems.Items
|
||||
// .Select(i =>
|
||||
// {
|
||||
// var artist = i.Item1;
|
||||
|
@ -1044,7 +1049,6 @@ namespace Emby.Server.Implementations.Dto
|
|||
}
|
||||
|
||||
return null;
|
||||
|
||||
}).Where(i => i != null).ToArray();
|
||||
}
|
||||
|
||||
|
@ -1158,7 +1162,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
// this block will add the series poster for episodes without a poster
|
||||
// TODO maybe remove the if statement entirely
|
||||
//if (options.ContainsField(ItemFields.SeriesPrimaryImage))
|
||||
// if (options.ContainsField(ItemFields.SeriesPrimaryImage))
|
||||
{
|
||||
episodeSeries = episodeSeries ?? episode.Series;
|
||||
if (episodeSeries != null)
|
||||
|
@ -1204,7 +1208,7 @@ namespace Emby.Server.Implementations.Dto
|
|||
|
||||
// this block will add the series poster for seasons without a poster
|
||||
// TODO maybe remove the if statement entirely
|
||||
//if (options.ContainsField(ItemFields.SeriesPrimaryImage))
|
||||
// if (options.ContainsField(ItemFields.SeriesPrimaryImage))
|
||||
{
|
||||
series = series ?? season.Series;
|
||||
if (series != null)
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
@ -131,7 +132,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
|
@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
|
||||
private async Task SendMessage(string name, TimerEventInfo info)
|
||||
{
|
||||
var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id).ToList();
|
||||
var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Class RefreshUsersMetadata.
|
||||
/// </summary>
|
||||
public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The user manager.
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
|
||||
/// </summary>
|
||||
public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Refresh Users";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Key => "RefreshUsers";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "Refresh user infos";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Category => "Library";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsHidden => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnabled => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLogged => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
foreach (var user in _userManager.Users)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TaskTriggerInfo
|
||||
{
|
||||
IntervalTicks = TimeSpan.FromDays(1).Ticks,
|
||||
Type = TaskTriggerInfo.TriggerInterval
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,10 +3,10 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
@ -68,10 +68,8 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
/// <inheritdoc />
|
||||
public Task RunAsync()
|
||||
{
|
||||
_userManager.UserDeleted += OnUserDeleted;
|
||||
_userManager.UserUpdated += OnUserUpdated;
|
||||
_userManager.UserPolicyUpdated += OnUserPolicyUpdated;
|
||||
_userManager.UserConfigurationUpdated += OnUserConfigurationUpdated;
|
||||
_userManager.OnUserDeleted += OnUserDeleted;
|
||||
_userManager.OnUserUpdated += OnUserUpdated;
|
||||
|
||||
_appHost.HasPendingRestartChanged += OnHasPendingRestartChanged;
|
||||
|
||||
|
@ -153,20 +151,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserPolicyUpdated(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
var dto = _userManager.GetUserDto(e.Argument);
|
||||
|
||||
await SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserConfigurationUpdated(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
var dto = _userManager.GetUserDto(e.Argument);
|
||||
|
||||
await SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task SendMessageToAdminSessions<T>(string name, T data)
|
||||
{
|
||||
try
|
||||
|
@ -175,7 +159,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +174,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,10 +192,8 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
{
|
||||
if (dispose)
|
||||
{
|
||||
_userManager.UserDeleted -= OnUserDeleted;
|
||||
_userManager.UserUpdated -= OnUserUpdated;
|
||||
_userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
|
||||
_userManager.UserConfigurationUpdated -= OnUserConfigurationUpdated;
|
||||
_userManager.OnUserDeleted -= OnUserDeleted;
|
||||
_userManager.OnUserUpdated -= OnUserUpdated;
|
||||
|
||||
_installationManager.PluginUninstalled -= OnPluginUninstalled;
|
||||
_installationManager.PackageInstalling -= OnPackageInstalling;
|
||||
|
|
|
@ -43,7 +43,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
_logger = logger;
|
||||
_appHost = appHost;
|
||||
_config = configuration;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
@ -580,7 +580,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Emby.Server.Implementations.SocketSharp;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
@ -90,7 +91,8 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
!string.IsNullOrEmpty(auth.Client) &&
|
||||
!string.IsNullOrEmpty(auth.Device))
|
||||
{
|
||||
_sessionManager.LogSessionActivity(auth.Client,
|
||||
_sessionManager.LogSessionActivity(
|
||||
auth.Client,
|
||||
auth.Version,
|
||||
auth.DeviceId,
|
||||
auth.Device,
|
||||
|
@ -104,21 +106,21 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
private void ValidateUserAccess(
|
||||
User user,
|
||||
IRequest request,
|
||||
IAuthenticationAttributes authAttribtues,
|
||||
IAuthenticationAttributes authAttributes,
|
||||
AuthorizationInfo auth)
|
||||
{
|
||||
if (user.Policy.IsDisabled)
|
||||
if (user.HasPermission(PermissionKind.IsDisabled))
|
||||
{
|
||||
throw new SecurityException("User account has been disabled.");
|
||||
}
|
||||
|
||||
if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
|
||||
if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !_networkManager.IsInLocalNetwork(request.RemoteIp))
|
||||
{
|
||||
throw new SecurityException("User account has been disabled.");
|
||||
}
|
||||
|
||||
if (!user.Policy.IsAdministrator
|
||||
&& !authAttribtues.EscapeParentalControl
|
||||
if (!user.HasPermission(PermissionKind.IsAdministrator)
|
||||
&& !authAttributes.EscapeParentalControl
|
||||
&& !user.IsParentalScheduleAllowed())
|
||||
{
|
||||
request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
|
||||
|
@ -180,7 +182,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (user == null || !user.Policy.IsAdministrator)
|
||||
if (user == null || !user.HasPermission(PermissionKind.IsAdministrator))
|
||||
{
|
||||
throw new SecurityException("User does not have admin access.");
|
||||
}
|
||||
|
@ -188,7 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
|
||||
if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (user == null || !user.Policy.EnableContentDeletion)
|
||||
if (user == null || !user.HasPermission(PermissionKind.EnableContentDeletion))
|
||||
{
|
||||
throw new SecurityException("User does not have delete access.");
|
||||
}
|
||||
|
@ -196,7 +198,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
|
||||
if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (user == null || !user.Policy.EnableContentDownloading)
|
||||
if (user == null || !user.HasPermission(PermissionKind.EnableContentDownloading))
|
||||
{
|
||||
throw new SecurityException("User does not have download access.");
|
||||
}
|
||||
|
@ -223,7 +225,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
throw new AuthenticationException("Access token is invalid or expired.");
|
||||
}
|
||||
|
||||
//if (!string.IsNullOrEmpty(info.UserId))
|
||||
// if (!string.IsNullOrEmpty(info.UserId))
|
||||
//{
|
||||
// var user = _userManager.GetUserById(info.UserId);
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
info.Device = tokenInfo.DeviceName;
|
||||
}
|
||||
|
||||
else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (allowTokenInfoUpdate)
|
||||
|
@ -149,9 +148,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
{
|
||||
info.User = _userManager.GetUserById(tokenInfo.UserId);
|
||||
|
||||
if (info.User != null && !string.Equals(info.User.Name, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
|
||||
if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
tokenInfo.UserName = info.User.Name;
|
||||
tokenInfo.UserName = info.User.Username;
|
||||
updateToken = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Security;
|
||||
|
|
|
@ -234,10 +234,12 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
private Task SendKeepAliveResponse()
|
||||
{
|
||||
LastKeepAliveDate = DateTime.UtcNow;
|
||||
return SendAsync(new WebSocketMessage<string>
|
||||
{
|
||||
MessageType = "KeepAlive"
|
||||
}, CancellationToken.None);
|
||||
return SendAsync(
|
||||
new WebSocketMessage<string>
|
||||
{
|
||||
MessageId = Guid.NewGuid(),
|
||||
MessageType = "KeepAlive"
|
||||
}, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
@ -266,7 +266,6 @@ namespace Emby.Server.Implementations.IO
|
|||
{
|
||||
DisposeWatcher(newWatcher, false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -393,7 +392,6 @@ namespace Emby.Server.Implementations.IO
|
|||
}
|
||||
|
||||
return false;
|
||||
|
||||
}))
|
||||
{
|
||||
monitorPath = false;
|
||||
|
|
|
@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.IO
|
|||
{
|
||||
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
|
||||
|
||||
//if (!result.IsDirectory)
|
||||
// if (!result.IsDirectory)
|
||||
//{
|
||||
// result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
|
||||
//}
|
||||
|
|
|
@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.Images
|
|||
new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending)
|
||||
},
|
||||
IncludeItemTypes = includeItemTypes
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ namespace Emby.Server.Implementations.Images
|
|||
}
|
||||
|
||||
return i;
|
||||
|
||||
}).GroupBy(x => x.Id)
|
||||
.Select(x => x.First());
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ using Emby.Server.Implementations.Library.Resolvers;
|
|||
using Emby.Server.Implementations.Library.Validators;
|
||||
using Emby.Server.Implementations.Playlists;
|
||||
using Emby.Server.Implementations.ScheduledTasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller;
|
||||
|
@ -25,7 +27,6 @@ using MediaBrowser.Controller.Drawing;
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
|
@ -46,6 +47,9 @@ using MediaBrowser.Model.Querying;
|
|||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Providers.MediaInfo;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Person = MediaBrowser.Controller.Entities.Person;
|
||||
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
|
||||
using VideoResolver = Emby.Naming.Video.VideoResolver;
|
||||
|
||||
|
@ -1539,7 +1543,8 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
// Handle grouping
|
||||
if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0)
|
||||
if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)
|
||||
&& user.GetPreference(PreferenceKind.GroupedFolders).Length > 0)
|
||||
{
|
||||
return GetUserRootFolder()
|
||||
.GetChildren(user, true)
|
||||
|
@ -2590,7 +2595,7 @@ namespace Emby.Server.Implementations.Library
|
|||
Anime series don't generally have a season in their file name, however,
|
||||
tvdb needs a season to correctly get the metadata.
|
||||
Hence, a null season needs to be filled with something. */
|
||||
//FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
|
||||
// FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
|
||||
episode.ParentIndexNumber = 1;
|
||||
}
|
||||
|
||||
|
@ -2856,7 +2861,6 @@ namespace Emby.Server.Implementations.Library
|
|||
_logger.LogError(ex, "Error getting person");
|
||||
return null;
|
||||
}
|
||||
|
||||
}).Where(i => i != null).ToList();
|
||||
}
|
||||
|
||||
|
@ -2986,7 +2990,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
private static bool ValidateNetworkPath(string path)
|
||||
{
|
||||
//if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
// if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
//{
|
||||
// // We can't validate protocol-based paths, so just allow them
|
||||
// if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
mediaInfo = _json.DeserializeFromFile<MediaInfo>(cacheFilePath);
|
||||
|
||||
//_logger.LogDebug("Found cached media info");
|
||||
// _logger.LogDebug("Found cached media info");
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.Library
|
|||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||
_json.SerializeToFile(mediaInfo, cacheFilePath);
|
||||
|
||||
//_logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,17 +148,14 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
videoStream.BitRate = 30000000;
|
||||
}
|
||||
|
||||
else if (width >= 1900)
|
||||
{
|
||||
videoStream.BitRate = 20000000;
|
||||
}
|
||||
|
||||
else if (width >= 1200)
|
||||
{
|
||||
videoStream.BitRate = 8000000;
|
||||
}
|
||||
|
||||
else if (width >= 700)
|
||||
{
|
||||
videoStream.BitRate = 2000000;
|
||||
|
|
|
@ -7,6 +7,8 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -14,7 +16,6 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -190,10 +191,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!user.Policy.EnableAudioPlaybackTranscoding)
|
||||
{
|
||||
source.SupportsTranscoding = false;
|
||||
}
|
||||
source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +350,9 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
|
||||
{
|
||||
if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
|
||||
if (userData.SubtitleStreamIndex.HasValue
|
||||
&& user.RememberSubtitleSelections
|
||||
&& user.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
|
||||
{
|
||||
var index = userData.SubtitleStreamIndex.Value;
|
||||
// Make sure the saved index is still valid
|
||||
|
@ -363,26 +363,27 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
|
||||
? Array.Empty<string>() : NormalizeLanguage(user.Configuration.SubtitleLanguagePreference);
|
||||
|
||||
var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference)
|
||||
? Array.Empty<string>() : NormalizeLanguage(user.SubtitleLanguagePreference);
|
||||
|
||||
var defaultAudioIndex = source.DefaultAudioStreamIndex;
|
||||
var audioLangage = defaultAudioIndex == null
|
||||
? null
|
||||
: source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
|
||||
|
||||
source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
|
||||
source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(
|
||||
source.MediaStreams,
|
||||
preferredSubs,
|
||||
user.Configuration.SubtitleMode,
|
||||
user.SubtitleMode,
|
||||
audioLangage);
|
||||
|
||||
MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
|
||||
user.Configuration.SubtitleMode, audioLangage);
|
||||
MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, user.SubtitleMode, audioLangage);
|
||||
}
|
||||
|
||||
private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
|
||||
{
|
||||
if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
|
||||
if (userData.AudioStreamIndex.HasValue && user.RememberAudioSelections && allowRememberingSelection)
|
||||
{
|
||||
var index = userData.AudioStreamIndex.Value;
|
||||
// Make sure the saved index is still valid
|
||||
|
@ -393,11 +394,11 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
}
|
||||
|
||||
var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
|
||||
var preferredAudio = string.IsNullOrEmpty(user.AudioLanguagePreference)
|
||||
? Array.Empty<string>()
|
||||
: NormalizeLanguage(user.Configuration.AudioLanguagePreference);
|
||||
: NormalizeLanguage(user.AudioLanguagePreference);
|
||||
|
||||
source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
|
||||
source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
|
||||
}
|
||||
|
||||
public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user)
|
||||
|
@ -435,7 +436,6 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
|
||||
.ThenByDescending(i =>
|
||||
{
|
||||
|
@ -534,7 +534,7 @@ namespace Emby.Server.Implementations.Library
|
|||
mediaSource.RunTimeTicks = null;
|
||||
}
|
||||
|
||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio);
|
||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||
|
||||
if (audioStream == null || audioStream.Index == -1)
|
||||
{
|
||||
|
@ -545,7 +545,7 @@ namespace Emby.Server.Implementations.Library
|
|||
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
|
||||
}
|
||||
|
||||
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video);
|
||||
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
||||
if (videoStream != null)
|
||||
{
|
||||
if (!videoStream.BitRate.HasValue)
|
||||
|
@ -556,17 +556,14 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
videoStream.BitRate = 30000000;
|
||||
}
|
||||
|
||||
else if (width >= 1900)
|
||||
{
|
||||
videoStream.BitRate = 20000000;
|
||||
}
|
||||
|
||||
else if (width >= 1200)
|
||||
{
|
||||
videoStream.BitRate = 8000000;
|
||||
}
|
||||
|
||||
else if (width >= 700)
|
||||
{
|
||||
videoStream.BitRate = 2000000;
|
||||
|
@ -622,7 +619,6 @@ namespace Emby.Server.Implementations.Library
|
|||
MediaSource = mediaSource,
|
||||
ExtractChapters = false,
|
||||
MediaType = DlnaProfileType.Video
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
mediaSource.MediaStreams = info.MediaStreams;
|
||||
|
@ -648,7 +644,7 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
mediaInfo = _jsonSerializer.DeserializeFromFile<MediaInfo>(cacheFilePath);
|
||||
|
||||
//_logger.LogDebug("Found cached media info");
|
||||
// _logger.LogDebug("Found cached media info");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -670,20 +666,21 @@ namespace Emby.Server.Implementations.Library
|
|||
mediaSource.AnalyzeDurationMs = 3000;
|
||||
}
|
||||
|
||||
mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||
mediaInfo = await _mediaEncoder.GetMediaInfo(
|
||||
new MediaInfoRequest
|
||||
{
|
||||
MediaSource = mediaSource,
|
||||
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
||||
ExtractChapters = false
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (cacheFilePath != null)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||
_jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath);
|
||||
|
||||
//_logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,17 +746,14 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
videoStream.BitRate = 30000000;
|
||||
}
|
||||
|
||||
else if (width >= 1900)
|
||||
{
|
||||
videoStream.BitRate = 20000000;
|
||||
}
|
||||
|
||||
else if (width >= 1200)
|
||||
{
|
||||
videoStream.BitRate = 8000000;
|
||||
}
|
||||
|
||||
else if (width >= 700)
|
||||
{
|
||||
videoStream.BitRate = 2000000;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
@ -10,6 +11,7 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
@ -75,7 +77,6 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
}).Where(i => !i.Equals(Guid.Empty)).ToArray();
|
||||
|
||||
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
|
||||
|
@ -105,32 +106,27 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetInstantMixFromGenreIds(new[] { item.Id }, user, dtoOptions);
|
||||
}
|
||||
|
||||
var playlist = item as Playlist;
|
||||
if (playlist != null)
|
||||
if (item is Playlist playlist)
|
||||
{
|
||||
return GetInstantMixFromPlaylist(playlist, user, dtoOptions);
|
||||
}
|
||||
|
||||
var album = item as MusicAlbum;
|
||||
if (album != null)
|
||||
if (item is MusicAlbum album)
|
||||
{
|
||||
return GetInstantMixFromAlbum(album, user, dtoOptions);
|
||||
}
|
||||
|
||||
var artist = item as MusicArtist;
|
||||
if (artist != null)
|
||||
if (item is MusicArtist artist)
|
||||
{
|
||||
return GetInstantMixFromArtist(artist, user, dtoOptions);
|
||||
}
|
||||
|
||||
var song = item as Audio;
|
||||
if (song != null)
|
||||
if (item is Audio song)
|
||||
{
|
||||
return GetInstantMixFromSong(song, user, dtoOptions);
|
||||
}
|
||||
|
||||
var folder = item as Folder;
|
||||
if (folder != null)
|
||||
if (item is Folder folder)
|
||||
{
|
||||
return GetInstantMixFromFolder(folder, user, dtoOptions);
|
||||
}
|
||||
|
|
|
@ -209,8 +209,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||
Name = parseName ?
|
||||
resolvedItem.Name :
|
||||
Path.GetFileNameWithoutExtension(firstMedia.Path),
|
||||
//AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
|
||||
//LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
|
||||
// AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
|
||||
// LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
|
||||
};
|
||||
|
||||
result.Items.Add(libraryItem);
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||
// Args points to an album if parent is an Artist folder or it directly contains music
|
||||
if (args.IsDirectory)
|
||||
{
|
||||
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice
|
||||
// if (args.Parent is MusicArtist) return true; // saves us from testing children twice
|
||||
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager))
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -292,7 +292,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
}
|
||||
|
||||
return true;
|
||||
//var blurayExtensions = new[]
|
||||
// var blurayExtensions = new[]
|
||||
//{
|
||||
// ".mts",
|
||||
// ".m2ts",
|
||||
|
@ -300,7 +300,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
// ".mpls"
|
||||
//};
|
||||
|
||||
//return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase));
|
||||
// return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
}
|
||||
if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new UserRootFolder(); //if we got here and still a root - must be user root
|
||||
return new UserRootFolder(); // if we got here and still a root - must be user root
|
||||
}
|
||||
if (args.IsVf)
|
||||
{
|
||||
|
@ -73,7 +73,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
})
|
||||
.Select(i => _fileSystem.GetFileNameWithoutExtension(i))
|
||||
.FirstOrDefault();
|
||||
|
|
|
@ -94,7 +94,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
_localization.GetLocalizedString("NameSeasonNumber"),
|
||||
seasonNumber,
|
||||
args.GetLibraryOptions().PreferredMetadataLanguage);
|
||||
|
||||
}
|
||||
|
||||
return season;
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
var collectionType = args.GetCollectionType();
|
||||
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
//if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
|
||||
// if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
|
||||
//{
|
||||
// return new Series
|
||||
// {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
@ -12,6 +13,8 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Search;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Person = MediaBrowser.Controller.Entities.Person;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
@ -204,7 +207,6 @@ namespace Emby.Server.Implementations.Library
|
|||
return mediaItems.Select(i => new SearchHintInfo
|
||||
{
|
||||
Item = i
|
||||
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Collections.Concurrent;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -13,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Book = MediaBrowser.Controller.Entities.Book;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,8 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
|
@ -17,6 +19,8 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Person = MediaBrowser.Controller.Entities.Person;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
|
@ -125,12 +129,12 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
if (!query.IncludeHidden)
|
||||
{
|
||||
list = list.Where(i => !user.Configuration.MyMediaExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
|
||||
list = list.Where(i => !user.GetPreference(PreferenceKind.MyMediaExcludes).Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
|
||||
}
|
||||
|
||||
var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
|
||||
|
||||
var orders = user.Configuration.OrderedViews.ToList();
|
||||
var orders = user.GetPreference(PreferenceKind.OrderedViews).ToList();
|
||||
|
||||
return list
|
||||
.OrderBy(i =>
|
||||
|
@ -165,7 +169,13 @@ namespace Emby.Server.Implementations.Library
|
|||
return GetUserSubViewWithName(name, parentId, type, sortName);
|
||||
}
|
||||
|
||||
private Folder GetUserView(List<ICollectionFolder> parents, string viewType, string localizationKey, string sortName, User user, string[] presetViews)
|
||||
private Folder GetUserView(
|
||||
List<ICollectionFolder> parents,
|
||||
string viewType,
|
||||
string localizationKey,
|
||||
string sortName,
|
||||
Jellyfin.Data.Entities.User user,
|
||||
string[] presetViews)
|
||||
{
|
||||
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
|
@ -270,7 +280,8 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
|
||||
.Where(i => i is Folder)
|
||||
.Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
|
||||
.Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes)
|
||||
.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
@ -331,12 +342,11 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
|
||||
{
|
||||
typeof(Person).Name,
|
||||
typeof(Studio).Name,
|
||||
typeof(Year).Name,
|
||||
typeof(MusicGenre).Name,
|
||||
typeof(Genre).Name
|
||||
|
||||
nameof(Person),
|
||||
nameof(Studio),
|
||||
nameof(Year),
|
||||
nameof(MusicGenre),
|
||||
nameof(Genre)
|
||||
} : Array.Empty<string>();
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
|
|
|
@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Library.Validators
|
|||
_libraryManager.DeleteItem(item, new DeleteOptions
|
||||
{
|
||||
DeleteFileLocation = false
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,6 @@ namespace Emby.Server.Implementations.Library.Validators
|
|||
_libraryManager.DeleteItem(item, new DeleteOptions
|
||||
{
|
||||
DeleteFileLocation = false
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -1547,7 +1547,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
IsFolder = false,
|
||||
Recursive = true,
|
||||
DtoOptions = new DtoOptions(true)
|
||||
|
||||
})
|
||||
.Where(i => i.IsFileProtocol && File.Exists(i.Path))
|
||||
.Skip(seriesTimer.KeepUpTo - 1)
|
||||
|
|
|
@ -183,7 +183,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
|
||||
|
||||
//var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
|
||||
// var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
|
||||
// " -f mp4 -movflags frag_keyframe+empty_moov" :
|
||||
// string.Empty;
|
||||
|
||||
|
@ -206,13 +206,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
{
|
||||
return "-codec:a:0 copy";
|
||||
|
||||
//var audioChannels = 2;
|
||||
//var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||
//if (audioStream != null)
|
||||
// var audioChannels = 2;
|
||||
// var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||
// if (audioStream != null)
|
||||
//{
|
||||
// audioChannels = audioStream.Channels ?? audioChannels;
|
||||
//}
|
||||
//return "-codec:a:0 aac -strict experimental -ab 320000";
|
||||
// return "-codec:a:0 aac -strict experimental -ab 320000";
|
||||
}
|
||||
|
||||
private static bool EncodeVideo(MediaSourceInfo mediaSource)
|
||||
|
|
|
@ -56,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
name += " " + info.EpisodeTitle;
|
||||
}
|
||||
}
|
||||
|
||||
else if (info.IsMovie && info.ProductionYear != null)
|
||||
{
|
||||
name += " (" + info.ProductionYear + ")";
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
var programsInfo = new List<ProgramInfo>();
|
||||
foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
|
||||
{
|
||||
//_logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
|
||||
// _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
|
||||
// " which corresponds to channel " + channelNumber + " and program id " +
|
||||
// schedule.programID + " which says it has images? " +
|
||||
// programDict[schedule.programID].hasImageArtwork);
|
||||
|
@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
|
||||
programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
|
||||
|
||||
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
||||
// programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
|
||||
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
|
||||
// GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
|
||||
// GetProgramImage(ApiUrl, data, "Banner-LOT", false);
|
||||
|
@ -276,7 +276,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
CommunityRating = null,
|
||||
EpisodeTitle = episodeTitle,
|
||||
Audio = audioType,
|
||||
//IsNew = programInfo.@new ?? false,
|
||||
// IsNew = programInfo.@new ?? false,
|
||||
IsRepeat = programInfo.@new == null,
|
||||
IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase),
|
||||
ImageUrl = details.primaryImage,
|
||||
|
@ -701,7 +701,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
CancellationToken = cancellationToken,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
//_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
|
||||
// _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
|
||||
// httpOptions.RequestContent);
|
||||
|
||||
using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
|
||||
|
@ -1218,7 +1218,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
public string programID { get; set; }
|
||||
public List<ImageData> data { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
|
@ -14,8 +16,6 @@ using MediaBrowser.Controller.Channels;
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
|
@ -31,6 +31,8 @@ using MediaBrowser.Model.Querying;
|
|||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
|
||||
namespace Emby.Server.Implementations.LiveTv
|
||||
{
|
||||
|
@ -404,8 +406,8 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
if (!(service is EmbyTV.EmbyTV))
|
||||
{
|
||||
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
|
||||
//mediaSource.SupportsDirectPlay = false;
|
||||
//mediaSource.SupportsDirectStream = false;
|
||||
// mediaSource.SupportsDirectPlay = false;
|
||||
// mediaSource.SupportsDirectStream = false;
|
||||
mediaSource.SupportsTranscoding = true;
|
||||
foreach (var stream in mediaSource.MediaStreams)
|
||||
{
|
||||
|
@ -556,7 +558,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
}
|
||||
item.ParentId = channel.Id;
|
||||
|
||||
//item.ChannelType = channelType;
|
||||
// item.ChannelType = channelType;
|
||||
|
||||
item.Audio = info.Audio;
|
||||
item.ChannelId = channel.Id;
|
||||
|
@ -696,7 +698,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
Path = info.ThumbImageUrl,
|
||||
Type = ImageType.Thumb
|
||||
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
@ -709,7 +710,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
Path = info.LogoImageUrl,
|
||||
Type = ImageType.Logo
|
||||
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
@ -722,7 +722,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
{
|
||||
Path = info.BackdropImageUrl,
|
||||
Type = ImageType.Backdrop
|
||||
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
@ -760,7 +759,8 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user);
|
||||
|
||||
var list = new List<Tuple<BaseItemDto, string, string>>() {
|
||||
var list = new List<Tuple<BaseItemDto, string, string>>
|
||||
{
|
||||
new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, program.ExternalSeriesId)
|
||||
};
|
||||
|
||||
|
@ -1168,7 +1168,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
|
||||
ChannelIds = new Guid[] { currentChannel.Id },
|
||||
DtoOptions = new DtoOptions(true)
|
||||
|
||||
}).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
|
||||
|
||||
var newPrograms = new List<LiveTvProgram>();
|
||||
|
@ -1368,10 +1367,10 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
// limit = (query.Limit ?? 10) * 2;
|
||||
limit = null;
|
||||
|
||||
//var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
|
||||
//var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
|
||||
// var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
|
||||
// var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
|
||||
|
||||
//return new QueryResult<BaseItem>
|
||||
// return new QueryResult<BaseItem>
|
||||
//{
|
||||
// Items = items,
|
||||
// TotalRecordCount = items.Length
|
||||
|
@ -1738,7 +1737,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
var results = await GetTimers(new TimerQuery
|
||||
{
|
||||
Id = id
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||
|
@ -1790,7 +1788,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
.Select(i =>
|
||||
{
|
||||
return i.Item1;
|
||||
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
|
@ -1845,7 +1842,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
}
|
||||
|
||||
return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName);
|
||||
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
|
@ -1878,7 +1874,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
|
||||
TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
|
||||
DtoOptions = options
|
||||
|
||||
}) : new List<BaseItem>();
|
||||
|
||||
RemoveFields(options);
|
||||
|
@ -1956,7 +1951,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
OriginalAirDate = program.PremiereDate,
|
||||
Overview = program.Overview,
|
||||
StartDate = program.StartDate,
|
||||
//ImagePath = program.ExternalImagePath,
|
||||
// ImagePath = program.ExternalImagePath,
|
||||
Name = program.Name,
|
||||
OfficialRating = program.OfficialRating
|
||||
};
|
||||
|
@ -2167,20 +2162,19 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
var info = new LiveTvInfo
|
||||
{
|
||||
Services = services,
|
||||
IsEnabled = services.Length > 0
|
||||
IsEnabled = services.Length > 0,
|
||||
EnabledUsers = _userManager.Users
|
||||
.Where(IsLiveTvEnabled)
|
||||
.Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
|
||||
.ToArray()
|
||||
};
|
||||
|
||||
info.EnabledUsers = _userManager.Users
|
||||
.Where(IsLiveTvEnabled)
|
||||
.Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
|
||||
.ToArray();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private bool IsLiveTvEnabled(User user)
|
||||
{
|
||||
return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
|
||||
return user.HasPermission(PermissionKind.EnableLiveTvAccess) && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
|
||||
}
|
||||
|
||||
public IEnumerable<User> GetEnabledUsers()
|
||||
|
@ -2457,7 +2451,6 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
UserId = user.Id,
|
||||
IsRecordingsFolder = true,
|
||||
RefreshLatestChannelItems = refreshChannels
|
||||
|
||||
}).Items);
|
||||
|
||||
return folders.Cast<BaseItem>().ToList();
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
|
||||
var list = result.ToList();
|
||||
//logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
|
||||
// logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
|
||||
|
||||
if (!string.IsNullOrEmpty(key) && list.Count > 0)
|
||||
{
|
||||
|
@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +115,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
ChannelType = ChannelType.TV,
|
||||
IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
|
||||
Path = i.URL
|
||||
|
||||
}).Cast<ChannelInfo>().ToList();
|
||||
}
|
||||
|
||||
|
@ -481,7 +480,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
Height = height,
|
||||
BitRate = videoBitrate,
|
||||
NalLengthSize = nal
|
||||
|
||||
},
|
||||
new MediaStream
|
||||
{
|
||||
|
@ -502,8 +500,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
SupportsTranscoding = true,
|
||||
IsInfiniteStream = true,
|
||||
IgnoreDts = true,
|
||||
//IgnoreIndex = true,
|
||||
//ReadAtNativeFramerate = true
|
||||
// IgnoreIndex = true,
|
||||
// ReadAtNativeFramerate = true
|
||||
};
|
||||
|
||||
mediaSource.InferTotalBitrate();
|
||||
|
@ -722,7 +720,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
|
|
@ -117,17 +117,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
taskCompletionSource,
|
||||
LiveStreamCancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
//OpenedMediaSource.Path = tempFile;
|
||||
//OpenedMediaSource.ReadAtNativeFramerate = true;
|
||||
// OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
// OpenedMediaSource.Path = tempFile;
|
||||
// OpenedMediaSource.ReadAtNativeFramerate = true;
|
||||
|
||||
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
|
||||
MediaSource.Protocol = MediaProtocol.Http;
|
||||
//OpenedMediaSource.SupportsDirectPlay = false;
|
||||
//OpenedMediaSource.SupportsDirectStream = true;
|
||||
//OpenedMediaSource.SupportsTranscoding = true;
|
||||
// OpenedMediaSource.SupportsDirectPlay = false;
|
||||
// OpenedMediaSource.SupportsDirectStream = true;
|
||||
// OpenedMediaSource.SupportsTranscoding = true;
|
||||
|
||||
//await Task.Delay(5000).ConfigureAwait(false);
|
||||
// await Task.Delay(5000).ConfigureAwait(false);
|
||||
await taskCompletionSource.Task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -220,11 +220,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
{
|
||||
using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!IsValidChannelNumber(numberString))
|
||||
|
@ -284,7 +283,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
|
||||
{
|
||||
//channel.Number = number.ToString();
|
||||
// channel.Number = number.ToString();
|
||||
nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,21 +103,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
_ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
|
||||
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
//OpenedMediaSource.Path = tempFile;
|
||||
//OpenedMediaSource.ReadAtNativeFramerate = true;
|
||||
// OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
// OpenedMediaSource.Path = tempFile;
|
||||
// OpenedMediaSource.ReadAtNativeFramerate = true;
|
||||
|
||||
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
|
||||
MediaSource.Protocol = MediaProtocol.Http;
|
||||
|
||||
//OpenedMediaSource.Path = TempFilePath;
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
// OpenedMediaSource.Path = TempFilePath;
|
||||
// OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
|
||||
//OpenedMediaSource.Path = _tempFilePath;
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
//OpenedMediaSource.SupportsDirectPlay = false;
|
||||
//OpenedMediaSource.SupportsDirectStream = true;
|
||||
//OpenedMediaSource.SupportsTranscoding = true;
|
||||
// OpenedMediaSource.Path = _tempFilePath;
|
||||
// OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
// OpenedMediaSource.SupportsDirectPlay = false;
|
||||
// OpenedMediaSource.SupportsDirectStream = true;
|
||||
// OpenedMediaSource.SupportsTranscoding = true;
|
||||
await taskCompletionSource.Task.ConfigureAwait(false);
|
||||
if (taskCompletionSource.Task.Exception != null)
|
||||
{
|
||||
|
|
|
@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Net
|
|||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -109,12 +108,11 @@ namespace Emby.Server.Implementations.Net
|
|||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||
// retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
|
||||
|
||||
var localIp = IPAddress.Any;
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace Emby.Server.Implementations.Networking
|
|||
|
||||
foreach (var subnet_Match in subnets)
|
||||
{
|
||||
//logger.LogDebug("subnet_Match:" + subnet_Match);
|
||||
// logger.LogDebug("subnet_Match:" + subnet_Match);
|
||||
|
||||
if (endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
@ -44,7 +45,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||
}
|
||||
|
||||
query.Recursive = true;
|
||||
query.IncludeItemTypes = new string[] { "Playlist" };
|
||||
query.IncludeItemTypes = new[] { "Playlist" };
|
||||
query.Parent = null;
|
||||
return LibraryManager.GetItemsResult(query);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
|
@ -21,6 +22,8 @@ using Microsoft.Extensions.Configuration;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using PlaylistsNET.Content;
|
||||
using PlaylistsNET.Models;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
|
||||
|
||||
namespace Emby.Server.Implementations.Playlists
|
||||
{
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
//TODO Investigate and properly fix.
|
||||
// TODO Investigate and properly fix.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ namespace Emby.Server.Implementations.Security
|
|||
AddColumn(db, "AccessTokens", "UserName", "TEXT", existingColumnNames);
|
||||
AddColumn(db, "AccessTokens", "DateLastActivity", "DATETIME", existingColumnNames);
|
||||
AddColumn(db, "AccessTokens", "AppVersion", "TEXT", existingColumnNames);
|
||||
|
||||
}, TransactionMode);
|
||||
|
||||
connection.RunQueries(new[]
|
||||
|
@ -107,7 +106,6 @@ namespace Emby.Server.Implementations.Security
|
|||
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +365,6 @@ namespace Emby.Server.Implementations.Security
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
}, ReadTransactionMode);
|
||||
}
|
||||
}
|
||||
|
@ -398,7 +395,6 @@ namespace Emby.Server.Implementations.Security
|
|||
|
||||
statement.MoveNext();
|
||||
}
|
||||
|
||||
}, TransactionMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace Emby.Server.Implementations.Services
|
|||
}
|
||||
}
|
||||
|
||||
//ContentType='text/html' is the default for a HttpResponse
|
||||
//Do not override if another has been set
|
||||
// ContentType='text/html' is the default for a HttpResponse
|
||||
// Do not override if another has been set
|
||||
if (response.ContentType == null || response.ContentType == "text/html")
|
||||
{
|
||||
response.ContentType = defaultContentType;
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
|
||||
|
||||
//var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
|
||||
//var responseType = returnMarker != null ?
|
||||
// var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
|
||||
// var responseType = returnMarker != null ?
|
||||
// GetGenericArguments(returnMarker)[0]
|
||||
// : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
|
||||
// mi.ReturnType
|
||||
|
@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Services
|
|||
serviceRequiresContext.Request = req;
|
||||
}
|
||||
|
||||
//Executes the service and returns the result
|
||||
// Executes the service and returns the result
|
||||
return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
var componentsList = new List<string>();
|
||||
|
||||
//We only split on '.' if the restPath has them. Allows for /{action}.{type}
|
||||
// We only split on '.' if the restPath has them. Allows for /{action}.{type}
|
||||
var hasSeparators = new List<bool>();
|
||||
foreach (var component in this.restPath.Split(PathSeperatorChar))
|
||||
{
|
||||
|
@ -298,12 +298,12 @@ namespace Emby.Server.Implementations.Services
|
|||
return -1;
|
||||
}
|
||||
|
||||
//Routes with least wildcard matches get the highest score
|
||||
// Routes with least wildcard matches get the highest score
|
||||
var score = Math.Max((100 - wildcardMatchCount), 1) * 1000
|
||||
//Routes with less variable (and more literal) matches
|
||||
// Routes with less variable (and more literal) matches
|
||||
+ Math.Max((10 - VariableArgsCount), 1) * 100;
|
||||
|
||||
//Exact verb match is better than ANY
|
||||
// Exact verb match is better than ANY
|
||||
if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
score += 10;
|
||||
|
@ -470,7 +470,7 @@ namespace Emby.Server.Implementations.Services
|
|||
+ variableName + " on " + RequestType.GetMethodName());
|
||||
}
|
||||
|
||||
var value = requestComponents.Length > pathIx ? requestComponents[pathIx] : null; //wildcard has arg mismatch
|
||||
var value = requestComponents.Length > pathIx ? requestComponents[pathIx] : null; // wildcard has arg mismatch
|
||||
if (value != null && this.isWildcard[i])
|
||||
{
|
||||
if (i == this.TotalComponentsCount - 1)
|
||||
|
@ -519,8 +519,8 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
if (queryStringAndFormData != null)
|
||||
{
|
||||
//Query String and form data can override variable path matches
|
||||
//path variables < query string < form data
|
||||
// Query String and form data can override variable path matches
|
||||
// path variables < query string < form data
|
||||
foreach (var name in queryStringAndFormData)
|
||||
{
|
||||
requestKeyValuesMap[name.Key] = name.Value;
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
if (propertySerializerEntry.PropertyType == typeof(bool))
|
||||
{
|
||||
//InputExtensions.cs#530 MVC Checkbox helper emits extra hidden input field, generating 2 values, first is the real value
|
||||
// InputExtensions.cs#530 MVC Checkbox helper emits extra hidden input field, generating 2 values, first is the real value
|
||||
propertyTextValue = StringExtensions.LeftPart(propertyTextValue, ',').ToString();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
|
@ -15,7 +17,6 @@ using MediaBrowser.Controller.Devices;
|
|||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Security;
|
||||
|
@ -28,7 +29,9 @@ using MediaBrowser.Model.Library;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
|
||||
namespace Emby.Server.Implementations.Session
|
||||
{
|
||||
|
@ -283,11 +286,18 @@ namespace Emby.Server.Implementations.Session
|
|||
if (user != null)
|
||||
{
|
||||
var userLastActivityDate = user.LastActivityDate ?? DateTime.MinValue;
|
||||
user.LastActivityDate = activityDate;
|
||||
|
||||
if ((activityDate - userLastActivityDate).TotalSeconds > 60)
|
||||
{
|
||||
_userManager.UpdateUser(user);
|
||||
try
|
||||
{
|
||||
user.LastActivityDate = activityDate;
|
||||
_userManager.UpdateUser(user);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
_logger.LogWarning(e, "Error updating user's last activity date.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,7 +444,13 @@ namespace Emby.Server.Implementations.Session
|
|||
/// <param name="remoteEndPoint">The remote end point.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>SessionInfo.</returns>
|
||||
private SessionInfo GetSessionInfo(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
|
||||
private SessionInfo GetSessionInfo(
|
||||
string appName,
|
||||
string appVersion,
|
||||
string deviceId,
|
||||
string deviceName,
|
||||
string remoteEndPoint,
|
||||
User user)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
|
@ -447,14 +463,13 @@ namespace Emby.Server.Implementations.Session
|
|||
|
||||
CheckDisposed();
|
||||
|
||||
var sessionInfo = _activeConnections.GetOrAdd(key, k =>
|
||||
{
|
||||
return CreateSession(k, appName, appVersion, deviceId, deviceName, remoteEndPoint, user);
|
||||
});
|
||||
var sessionInfo = _activeConnections.GetOrAdd(
|
||||
key,
|
||||
k => CreateSession(k, appName, appVersion, deviceId, deviceName, remoteEndPoint, user));
|
||||
|
||||
sessionInfo.UserId = user == null ? Guid.Empty : user.Id;
|
||||
sessionInfo.UserName = user?.Name;
|
||||
sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary);
|
||||
sessionInfo.UserId = user?.Id ?? Guid.Empty;
|
||||
sessionInfo.UserName = user?.Username;
|
||||
sessionInfo.UserPrimaryImageTag = user?.ProfileImage == null ? null : GetImageCacheTag(user);
|
||||
sessionInfo.RemoteEndPoint = remoteEndPoint;
|
||||
sessionInfo.Client = appName;
|
||||
|
||||
|
@ -473,7 +488,14 @@ namespace Emby.Server.Implementations.Session
|
|||
return sessionInfo;
|
||||
}
|
||||
|
||||
private SessionInfo CreateSession(string key, string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
|
||||
private SessionInfo CreateSession(
|
||||
string key,
|
||||
string appName,
|
||||
string appVersion,
|
||||
string deviceId,
|
||||
string deviceName,
|
||||
string remoteEndPoint,
|
||||
User user)
|
||||
{
|
||||
var sessionInfo = new SessionInfo(this, _logger)
|
||||
{
|
||||
|
@ -483,11 +505,11 @@ namespace Emby.Server.Implementations.Session
|
|||
Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
var username = user?.Name;
|
||||
var username = user?.Username;
|
||||
|
||||
sessionInfo.UserId = user?.Id ?? Guid.Empty;
|
||||
sessionInfo.UserName = username;
|
||||
sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary);
|
||||
sessionInfo.UserPrimaryImageTag = user?.ProfileImage == null ? null : GetImageCacheTag(user);
|
||||
sessionInfo.RemoteEndPoint = remoteEndPoint;
|
||||
|
||||
if (string.IsNullOrEmpty(deviceName))
|
||||
|
@ -535,10 +557,7 @@ namespace Emby.Server.Implementations.Session
|
|||
|
||||
private void StartIdleCheckTimer()
|
||||
{
|
||||
if (_idleTimer == null)
|
||||
{
|
||||
_idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
||||
}
|
||||
_idleTimer ??= new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
||||
}
|
||||
|
||||
private void StopIdleCheckTimer()
|
||||
|
@ -786,7 +805,7 @@ namespace Emby.Server.Implementations.Session
|
|||
{
|
||||
var changed = false;
|
||||
|
||||
if (user.Configuration.RememberAudioSelections)
|
||||
if (user.RememberAudioSelections)
|
||||
{
|
||||
if (data.AudioStreamIndex != info.AudioStreamIndex)
|
||||
{
|
||||
|
@ -803,7 +822,7 @@ namespace Emby.Server.Implementations.Session
|
|||
}
|
||||
}
|
||||
|
||||
if (user.Configuration.RememberSubtitleSelections)
|
||||
if (user.RememberSubtitleSelections)
|
||||
{
|
||||
if (data.SubtitleStreamIndex != info.SubtitleStreamIndex)
|
||||
{
|
||||
|
@ -1114,13 +1133,13 @@ namespace Emby.Server.Implementations.Session
|
|||
if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name));
|
||||
string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Username));
|
||||
}
|
||||
}
|
||||
|
||||
if (user != null
|
||||
&& command.ItemIds.Length == 1
|
||||
&& user.Configuration.EnableNextEpisodeAutoPlay
|
||||
&& user.EnableNextEpisodeAutoPlay
|
||||
&& _libraryManager.GetItemById(command.ItemIds[0]) is Episode episode)
|
||||
{
|
||||
var series = episode.Series;
|
||||
|
@ -1191,7 +1210,7 @@ namespace Emby.Server.Implementations.Session
|
|||
DtoOptions = new DtoOptions(false)
|
||||
{
|
||||
EnableImages = false,
|
||||
Fields = new ItemFields[]
|
||||
Fields = new[]
|
||||
{
|
||||
ItemFields.SortName
|
||||
}
|
||||
|
@ -1353,7 +1372,7 @@ namespace Emby.Server.Implementations.Session
|
|||
list.Add(new SessionUserInfo
|
||||
{
|
||||
UserId = userId,
|
||||
UserName = user.Name
|
||||
UserName = user.Username
|
||||
});
|
||||
|
||||
session.AdditionalUsers = list.ToArray();
|
||||
|
@ -1513,7 +1532,7 @@ namespace Emby.Server.Implementations.Session
|
|||
DeviceName = deviceName,
|
||||
UserId = user.Id,
|
||||
AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
|
||||
UserName = user.Name
|
||||
UserName = user.Username
|
||||
};
|
||||
|
||||
_logger.LogInformation("Creating new access token for user {0}", user.Id);
|
||||
|
@ -1710,15 +1729,15 @@ namespace Emby.Server.Implementations.Session
|
|||
return info;
|
||||
}
|
||||
|
||||
private string GetImageCacheTag(BaseItem item, ImageType type)
|
||||
private string GetImageCacheTag(User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _imageProcessor.GetImageCacheTag(item, type);
|
||||
return _imageProcessor.GetImageCacheTag(user);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting image information for {Type}", type);
|
||||
_logger.LogError(e, "Error getting image information for profile image");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1827,7 +1846,10 @@ namespace Emby.Server.Implementations.Session
|
|||
{
|
||||
CheckDisposed();
|
||||
|
||||
var adminUserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToList();
|
||||
var adminUserIds = _userManager.Users
|
||||
.Where(i => i.HasPermission(PermissionKind.IsAdministrator))
|
||||
.Select(i => i.Id)
|
||||
.ToList();
|
||||
|
||||
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.Sorting
|
|||
|
||||
if (val != 0)
|
||||
{
|
||||
//return val;
|
||||
// return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
|
|
|
@ -102,20 +102,15 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
return new SessionInfo[] { from };
|
||||
case BroadcastType.AllGroup:
|
||||
return _group.Participants.Values.Select(
|
||||
session => session.Session
|
||||
).ToArray();
|
||||
session => session.Session).ToArray();
|
||||
case BroadcastType.AllExceptCurrentSession:
|
||||
return _group.Participants.Values.Select(
|
||||
session => session.Session
|
||||
).Where(
|
||||
session => !session.Id.Equals(from.Id)
|
||||
).ToArray();
|
||||
session => session.Session).Where(
|
||||
session => !session.Id.Equals(from.Id)).ToArray();
|
||||
case BroadcastType.AllReady:
|
||||
return _group.Participants.Values.Where(
|
||||
session => !session.IsBuffering
|
||||
).Select(
|
||||
session => session.Session
|
||||
).ToArray();
|
||||
session => !session.IsBuffering).Select(
|
||||
session => session.Session).ToArray();
|
||||
default:
|
||||
return Array.Empty<SessionInfo>();
|
||||
}
|
||||
|
@ -314,8 +309,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
// Playback synchronization will mainly happen client side
|
||||
_group.IsPaused = false;
|
||||
_group.LastActivity = DateTime.UtcNow.AddMilliseconds(
|
||||
delay
|
||||
);
|
||||
delay);
|
||||
|
||||
var command = NewSyncPlayCommand(SendCommandType.Play);
|
||||
SendCommand(session, BroadcastType.AllGroup, command, cancellationToken);
|
||||
|
@ -449,8 +443,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
// Client that was buffering is recovering, notifying others to resume
|
||||
_group.LastActivity = currentTime.AddMilliseconds(
|
||||
delay
|
||||
);
|
||||
delay);
|
||||
var command = NewSyncPlayCommand(SendCommandType.Play);
|
||||
SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken);
|
||||
}
|
||||
|
@ -461,8 +454,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
delay = delay < _group.DefaulPing ? _group.DefaulPing : delay;
|
||||
|
||||
_group.LastActivity = currentTime.AddMilliseconds(
|
||||
delay
|
||||
);
|
||||
delay);
|
||||
|
||||
var command = NewSyncPlayCommand(SendCommandType.Play);
|
||||
SendCommand(session, BroadcastType.AllGroup, command, cancellationToken);
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Controller.SyncPlay;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.SyncPlay
|
||||
{
|
||||
|
@ -109,14 +109,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
_disposed = true;
|
||||
}
|
||||
|
||||
private void CheckDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e)
|
||||
{
|
||||
var session = e.SessionInfo;
|
||||
|
@ -149,38 +141,24 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
var item = _libraryManager.GetItemById(itemId);
|
||||
|
||||
// Check ParentalRating access
|
||||
var hasParentalRatingAccess = true;
|
||||
if (user.Policy.MaxParentalRating.HasValue)
|
||||
{
|
||||
hasParentalRatingAccess = item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating;
|
||||
}
|
||||
var hasParentalRatingAccess = !user.MaxParentalAgeRating.HasValue
|
||||
|| item.InheritedParentalRatingValue <= user.MaxParentalAgeRating;
|
||||
|
||||
if (!user.Policy.EnableAllFolders && hasParentalRatingAccess)
|
||||
if (!user.HasPermission(PermissionKind.EnableAllFolders) && hasParentalRatingAccess)
|
||||
{
|
||||
var collections = _libraryManager.GetCollectionFolders(item).Select(
|
||||
folder => folder.Id.ToString("N", CultureInfo.InvariantCulture)
|
||||
);
|
||||
var intersect = collections.Intersect(user.Policy.EnabledFolders);
|
||||
return intersect.Any();
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasParentalRatingAccess;
|
||||
folder => folder.Id.ToString("N", CultureInfo.InvariantCulture));
|
||||
|
||||
return collections.Intersect(user.GetPreference(PreferenceKind.EnabledFolders)).Any();
|
||||
}
|
||||
|
||||
return hasParentalRatingAccess;
|
||||
}
|
||||
|
||||
private Guid? GetSessionGroup(SessionInfo session)
|
||||
{
|
||||
ISyncPlayController group;
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out group);
|
||||
if (group != null)
|
||||
{
|
||||
return group.GetGroupId();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out var group);
|
||||
return group?.GetGroupId();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -188,7 +166,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
var user = _userManager.GetUserById(session.UserId);
|
||||
|
||||
if (user.Policy.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups)
|
||||
if (user.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups)
|
||||
{
|
||||
_logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id);
|
||||
|
||||
|
@ -196,7 +174,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.CreateGroupDenied
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -219,7 +197,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
var user = _userManager.GetUserById(session.UserId);
|
||||
|
||||
if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
|
||||
if (user.SyncPlayAccess == SyncPlayAccess.None)
|
||||
{
|
||||
_logger.LogWarning("JoinGroup: {0} does not have access to SyncPlay.", session.Id);
|
||||
|
||||
|
@ -227,7 +205,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.JoinGroupDenied
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -244,7 +222,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.GroupDoesNotExist
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -257,7 +235,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
GroupId = group.GetGroupId().ToString(),
|
||||
Type = GroupUpdateType.LibraryAccessDenied
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -281,8 +259,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
// TODO: determine what happens to users that are in a group and get their permissions revoked
|
||||
lock (_groupsLock)
|
||||
{
|
||||
ISyncPlayController group;
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out group);
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out var group);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
|
@ -292,7 +269,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.NotInGroup
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -311,7 +288,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
var user = _userManager.GetUserById(session.UserId);
|
||||
|
||||
if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
|
||||
if (user.SyncPlayAccess == SyncPlayAccess.None)
|
||||
{
|
||||
return new List<GroupInfoView>();
|
||||
}
|
||||
|
@ -320,19 +297,15 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
if (!filterItemId.Equals(Guid.Empty))
|
||||
{
|
||||
return _groups.Values.Where(
|
||||
group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())
|
||||
).Select(
|
||||
group => group.GetInfo()
|
||||
).ToList();
|
||||
group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())).Select(
|
||||
group => group.GetInfo()).ToList();
|
||||
}
|
||||
// Otherwise show all available groups
|
||||
else
|
||||
{
|
||||
return _groups.Values.Where(
|
||||
group => HasAccessToItem(user, group.GetPlayingItemId())
|
||||
).Select(
|
||||
group => group.GetInfo()
|
||||
).ToList();
|
||||
group => HasAccessToItem(user, group.GetPlayingItemId())).Select(
|
||||
group => group.GetInfo()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,7 +314,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
var user = _userManager.GetUserById(session.UserId);
|
||||
|
||||
if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
|
||||
if (user.SyncPlayAccess == SyncPlayAccess.None)
|
||||
{
|
||||
_logger.LogWarning("HandleRequest: {0} does not have access to SyncPlay.", session.Id);
|
||||
|
||||
|
@ -349,14 +322,13 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.JoinGroupDenied
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_groupsLock)
|
||||
{
|
||||
ISyncPlayController group;
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out group);
|
||||
_sessionToGroupMap.TryGetValue(session.Id, out var group);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
|
@ -366,7 +338,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
{
|
||||
Type = GroupUpdateType.NotInGroup
|
||||
};
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
|
||||
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -393,8 +365,7 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||
throw new InvalidOperationException("Session not in any group!");
|
||||
}
|
||||
|
||||
ISyncPlayController tempGroup;
|
||||
_sessionToGroupMap.Remove(session.Id, out tempGroup);
|
||||
_sessionToGroupMap.Remove(session.Id, out var tempGroup);
|
||||
|
||||
if (!tempGroup.GetGroupId().Equals(group.GetGroupId()))
|
||||
{
|
||||
|
|
|
@ -4,13 +4,17 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
|
||||
namespace Emby.Server.Implementations.TV
|
||||
{
|
||||
|
@ -73,7 +77,8 @@ namespace Emby.Server.Implementations.TV
|
|||
{
|
||||
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
|
||||
.Where(i => i is Folder)
|
||||
.Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
|
||||
.Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes)
|
||||
.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
|
@ -144,7 +149,7 @@ namespace Emby.Server.Implementations.TV
|
|||
var allNextUp = seriesKeys
|
||||
.Select(i => GetNextUp(i, currentUser, dtoOptions));
|
||||
|
||||
//allNextUp = allNextUp.OrderByDescending(i => i.Item1);
|
||||
// allNextUp = allNextUp.OrderByDescending(i => i.Item1);
|
||||
|
||||
// If viewing all next up for all series, remove first episodes
|
||||
// But if that returns empty, keep those first episodes (avoid completely empty view)
|
||||
|
@ -191,7 +196,7 @@ namespace Emby.Server.Implementations.TV
|
|||
{
|
||||
AncestorWithPresentationUniqueKey = null,
|
||||
SeriesPresentationUniqueKey = seriesKey,
|
||||
IncludeItemTypes = new[] { typeof(Episode).Name },
|
||||
IncludeItemTypes = new[] { nameof(Episode) },
|
||||
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Descending) },
|
||||
IsPlayed = true,
|
||||
Limit = 1,
|
||||
|
@ -204,7 +209,6 @@ namespace Emby.Server.Implementations.TV
|
|||
},
|
||||
EnableImages = false
|
||||
}
|
||||
|
||||
}).FirstOrDefault();
|
||||
|
||||
Func<Episode> getEpisode = () =>
|
||||
|
@ -219,9 +223,8 @@ namespace Emby.Server.Implementations.TV
|
|||
IsPlayed = false,
|
||||
IsVirtualItem = false,
|
||||
ParentIndexNumberNotEquals = 0,
|
||||
MinSortName = lastWatchedEpisode == null ? null : lastWatchedEpisode.SortName,
|
||||
MinSortName = lastWatchedEpisode?.SortName,
|
||||
DtoOptions = dtoOptions
|
||||
|
||||
}).Cast<Episode>().FirstOrDefault();
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Security.Claims;
|
|||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -49,10 +50,10 @@ namespace Jellyfin.Api.Auth
|
|||
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim(ClaimTypes.Name, user.Name),
|
||||
new Claim(ClaimTypes.Name, user.Username),
|
||||
new Claim(
|
||||
ClaimTypes.Role,
|
||||
value: user.Policy.IsAdministrator ? UserRoles.Administrator : UserRoles.User)
|
||||
value: user.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, Scheme.Name);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
|
|
@ -95,10 +95,12 @@ namespace Jellyfin.Api.Controllers
|
|||
[HttpGet("User")]
|
||||
public StartupUserDto GetFirstUser()
|
||||
{
|
||||
// TODO: Remove this method when startup wizard no longer requires an existing user.
|
||||
_userManager.Initialize();
|
||||
var user = _userManager.Users.First();
|
||||
return new StartupUserDto
|
||||
{
|
||||
Name = user.Name,
|
||||
Name = user.Username,
|
||||
Password = user.Password
|
||||
};
|
||||
}
|
||||
|
@ -113,9 +115,9 @@ namespace Jellyfin.Api.Controllers
|
|||
{
|
||||
var user = _userManager.Users.First();
|
||||
|
||||
user.Name = startupUserDto.Name;
|
||||
user.Username = startupUserDto.Name;
|
||||
|
||||
_userManager.UpdateUser(user);
|
||||
await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(startupUserDto.Password))
|
||||
{
|
||||
|
|
65
Jellyfin.Data/DayOfWeekHelper.cs
Normal file
65
Jellyfin.Data/DayOfWeekHelper.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Data.Enums;
|
||||
|
||||
namespace Jellyfin.Data
|
||||
{
|
||||
public static class DayOfWeekHelper
|
||||
{
|
||||
public static List<DayOfWeek> GetDaysOfWeek(DynamicDayOfWeek day)
|
||||
{
|
||||
var days = new List<DayOfWeek>(7);
|
||||
|
||||
if (day == DynamicDayOfWeek.Sunday
|
||||
|| day == DynamicDayOfWeek.Weekend
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Sunday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Monday
|
||||
|| day == DynamicDayOfWeek.Weekday
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Monday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Tuesday
|
||||
|| day == DynamicDayOfWeek.Weekday
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Tuesday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Wednesday
|
||||
|| day == DynamicDayOfWeek.Weekday
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Wednesday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Thursday
|
||||
|| day == DynamicDayOfWeek.Weekday
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Thursday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Friday
|
||||
|| day == DynamicDayOfWeek.Weekday
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Friday);
|
||||
}
|
||||
|
||||
if (day == DynamicDayOfWeek.Saturday
|
||||
|| day == DynamicDayOfWeek.Weekend
|
||||
|| day == DynamicDayOfWeek.Everyday)
|
||||
{
|
||||
days.Add(DayOfWeek.Saturday);
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
}
|
||||
}
|
91
Jellyfin.Data/Entities/AccessSchedule.cs
Normal file
91
Jellyfin.Data/Entities/AccessSchedule.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Xml.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
|
||||
namespace Jellyfin.Data.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a user's access schedule.
|
||||
/// </summary>
|
||||
public class AccessSchedule
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AccessSchedule"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dayOfWeek">The day of the week.</param>
|
||||
/// <param name="startHour">The start hour.</param>
|
||||
/// <param name="endHour">The end hour.</param>
|
||||
/// <param name="userId">The associated user's id.</param>
|
||||
public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId)
|
||||
{
|
||||
UserId = userId;
|
||||
DayOfWeek = dayOfWeek;
|
||||
StartHour = startHour;
|
||||
EndHour = endHour;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AccessSchedule"/> class.
|
||||
/// Default constructor. Protected due to required properties, but present because EF needs it.
|
||||
/// </summary>
|
||||
protected AccessSchedule()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id of this instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Identity, Indexed, Required.
|
||||
/// </remarks>
|
||||
[XmlIgnore]
|
||||
[Key]
|
||||
[Required]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id of the associated user.
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
[Required]
|
||||
public Guid UserId { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the day of week.
|
||||
/// </summary>
|
||||
/// <value>The day of week.</value>
|
||||
[Required]
|
||||
public DynamicDayOfWeek DayOfWeek { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the start hour.
|
||||
/// </summary>
|
||||
/// <value>The start hour.</value>
|
||||
[Required]
|
||||
public double StartHour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the end hour.
|
||||
/// </summary>
|
||||
/// <value>The end hour.</value>
|
||||
[Required]
|
||||
public double EndHour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Static create function (for use in LINQ queries, etc.)
|
||||
/// </summary>
|
||||
/// <param name="dayOfWeek">The day of the week.</param>
|
||||
/// <param name="startHour">The start hour.</param>
|
||||
/// <param name="endHour">The end hour.</param>
|
||||
/// <param name="userId">The associated user's id.</param>
|
||||
/// <returns>The newly created instance.</returns>
|
||||
public static AccessSchedule Create(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId)
|
||||
{
|
||||
return new AccessSchedule(dayOfWeek, startHour, endHour, userId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -189,7 +189,6 @@ namespace Jellyfin.Data.Entities
|
|||
/*************************************************************************
|
||||
* Navigation properties
|
||||
*************************************************************************/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ namespace Jellyfin.Data.Entities
|
|||
|
||||
[ForeignKey("Release_Releases_Id")]
|
||||
public virtual ICollection<Release> Releases { get; protected set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,6 @@ namespace Jellyfin.Data.Entities
|
|||
|
||||
[ForeignKey("Company_Publishers_Id")]
|
||||
public virtual ICollection<Company> Publishers { get; protected set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user