mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-19 12:44:19 +01:00
Merge remote-tracking branch 'upstream/master' into hwaccel
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
using MediaBrowser.Model.Devices;
|
||||
|
||||
namespace MediaBrowser.Controller.Devices
|
||||
{
|
||||
public class CameraImageUploadInfo
|
||||
{
|
||||
public LocalFileInfo FileInfo { get; set; }
|
||||
public DeviceInfo Device { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,15 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <returns>The image dimensions.</returns>
|
||||
ImageDimensions GetImageSize(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blurhash of an image.
|
||||
/// </summary>
|
||||
/// <param name="xComp">Amount of X components of DCT to take.</param>
|
||||
/// <param name="yComp">Amount of Y components of DCT to take.</param>
|
||||
/// <param name="path">The filepath of the image.</param>
|
||||
/// <returns>The blurhash.</returns>
|
||||
string GetImageBlurHash(int xComp, int yComp, string path);
|
||||
|
||||
/// <summary>
|
||||
/// Encode an image.
|
||||
/// </summary>
|
||||
|
||||
@@ -40,6 +40,13 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <returns>ImageDimensions</returns>
|
||||
ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blurhash of the image.
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the image file.</param>
|
||||
/// <returns>BlurHash</returns>
|
||||
string GetImageBlurHash(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image cache tag.
|
||||
/// </summary>
|
||||
@@ -47,6 +54,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <param name="image">The image.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
string GetImageCacheTag(BaseItem item, ItemImageInfo image);
|
||||
|
||||
string GetImageCacheTag(BaseItem item, ChapterInfo info);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1374,6 +1374,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
new List<FileSystemMetadata>();
|
||||
|
||||
var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false);
|
||||
LibraryManager.UpdateImages(this); // ensure all image properties in DB are fresh
|
||||
|
||||
if (ownedItemsChanged)
|
||||
{
|
||||
@@ -2222,6 +2223,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
existingImage.DateModified = image.DateModified;
|
||||
existingImage.Width = image.Width;
|
||||
existingImage.Height = image.Height;
|
||||
existingImage.BlurHash = image.BlurHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2373,6 +2375,46 @@ namespace MediaBrowser.Controller.Entities
|
||||
.ElementAtOrDefault(imageIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes image index for given image or raises if no matching image found.
|
||||
/// </summary>
|
||||
/// <param name="image">Image to compute index for.</param>
|
||||
/// <exception cref="ArgumentException">Image index cannot be computed as no matching image found.
|
||||
/// </exception>
|
||||
/// <returns>Image index.</returns>
|
||||
public int GetImageIndex(ItemImageInfo image)
|
||||
{
|
||||
if (image == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(image));
|
||||
}
|
||||
|
||||
if (image.Type == ImageType.Chapter)
|
||||
{
|
||||
var chapters = ItemRepository.GetChapters(this);
|
||||
for (var i = 0; i < chapters.Count; i++)
|
||||
{
|
||||
if (chapters[i].ImagePath == image.Path)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("No chapter index found for image path", image.Path);
|
||||
}
|
||||
|
||||
var images = GetImages(image.Type).ToArray();
|
||||
for (var i = 0; i < images.Length; i++)
|
||||
{
|
||||
if (images[i].Path == image.Path)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("No image index found for image path", image.Path);
|
||||
}
|
||||
|
||||
public IEnumerable<ItemImageInfo> GetImages(ImageType imageType)
|
||||
{
|
||||
if (imageType == ImageType.Chapter)
|
||||
|
||||
@@ -11,6 +11,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override string MediaType => Model.Entities.MediaType.Book;
|
||||
|
||||
public override bool SupportsPlayedStatus => true;
|
||||
|
||||
public override bool SupportsPositionTicksResume => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPresentationUniqueKey { get; set; }
|
||||
|
||||
@@ -20,6 +24,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public Book()
|
||||
{
|
||||
this.RunTimeTicks = TimeSpan.TicksPerSecond;
|
||||
}
|
||||
|
||||
public string FindSeriesSortName()
|
||||
{
|
||||
return SeriesName;
|
||||
|
||||
@@ -341,6 +341,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
currentChild.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// metadata is up-to-date; make sure DB has correct images dimensions and hash
|
||||
LibraryManager.UpdateImages(currentChild);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the blurhash.
|
||||
/// </summary>
|
||||
/// <value>The blurhash.</value>
|
||||
public string BlurHash { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsLocalFile => Path == null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
void QueueLibraryScan();
|
||||
|
||||
void UpdateImages(BaseItem item);
|
||||
void UpdateImages(BaseItem item, bool forceUpdate = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default view.
|
||||
@@ -195,6 +195,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// Updates the item.
|
||||
/// </summary>
|
||||
void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||
|
||||
void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -143,14 +143,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>UserDto.</returns>
|
||||
UserDto GetUserDto(User user, string remoteEndPoint = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user public dto.
|
||||
/// </summary>
|
||||
/// <param name="user">Ther user.</param>\
|
||||
/// <param name="remoteEndPoint">The remote end point.</param>
|
||||
/// <returns>A public UserDto, aka a UserDto stripped of personal data.</returns>
|
||||
PublicUserDto GetPublicUserDto(User user, string remoteEndPoint = null);
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates the user.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
#nullable enable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class TimerEventInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public Guid ProgramId { get; set; }
|
||||
public TimerEventInfo(string id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
|
||||
public Guid? ProgramId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1352,7 +1352,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
transcoderChannelLimit = 6;
|
||||
}
|
||||
|
||||
var isTranscodingAudio = !string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase);
|
||||
var isTranscodingAudio = !EncodingHelper.IsCopyCodec(codec);
|
||||
|
||||
int? resultChannels = state.GetRequestedAudioChannels(codec);
|
||||
if (isTranscodingAudio)
|
||||
@@ -1748,7 +1748,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs)
|
||||
if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
||||
|| (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs))
|
||||
&& width.HasValue
|
||||
&& height.HasValue)
|
||||
{
|
||||
@@ -2005,7 +2006,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
filters.Add("hwupload");
|
||||
}
|
||||
|
||||
// When the input may or may not be hardware QSV decodable
|
||||
// When the input may or may not be hardware QSV decodable
|
||||
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!hasTextSubs)
|
||||
@@ -2262,7 +2263,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
flags.Add("+ignidx");
|
||||
}
|
||||
|
||||
if (state.GenPtsInput || string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (state.GenPtsInput || EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
|
||||
{
|
||||
flags.Add("+genpts");
|
||||
}
|
||||
@@ -2530,7 +2531,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase)
|
||||
|| videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -2941,7 +2943,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
args += " -mpegts_m2ts_mode 1";
|
||||
}
|
||||
|
||||
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (EncodingHelper.IsCopyCodec(videoCodec))
|
||||
{
|
||||
if (state.VideoStream != null
|
||||
&& string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -3043,7 +3045,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
var args = "-codec:a:0 " + codec;
|
||||
|
||||
if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (EncodingHelper.IsCopyCodec(codec))
|
||||
{
|
||||
return args;
|
||||
}
|
||||
@@ -3115,5 +3117,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
string.Empty,
|
||||
string.Empty).Trim();
|
||||
}
|
||||
|
||||
public static bool IsCopyCodec(string codec)
|
||||
{
|
||||
return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseRequest.BreakOnNonKeyFrames && string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase);
|
||||
return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -367,7 +367,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputAudioCodec))
|
||||
{
|
||||
if (AudioStream != null)
|
||||
{
|
||||
@@ -390,7 +390,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputAudioCodec))
|
||||
{
|
||||
if (AudioStream != null)
|
||||
{
|
||||
@@ -409,7 +409,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.Level;
|
||||
}
|
||||
@@ -433,7 +433,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.BitDepth;
|
||||
}
|
||||
@@ -451,7 +451,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.RefFrames;
|
||||
}
|
||||
@@ -468,7 +468,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream == null ? null : (VideoStream.AverageFrameRate ?? VideoStream.RealFrameRate);
|
||||
}
|
||||
@@ -499,7 +499,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.PacketLength;
|
||||
}
|
||||
@@ -515,7 +515,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.Profile;
|
||||
}
|
||||
@@ -535,7 +535,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.CodecTag;
|
||||
}
|
||||
@@ -549,7 +549,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.IsAnamorphic;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.Codec;
|
||||
}
|
||||
@@ -575,7 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (EncodingHelper.IsCopyCodec(OutputAudioCodec))
|
||||
{
|
||||
return AudioStream?.Codec;
|
||||
}
|
||||
@@ -589,7 +589,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static
|
||||
|| string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.IsInterlaced;
|
||||
}
|
||||
@@ -607,7 +607,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
|
||||
if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.IsAVC;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace MediaBrowser.Controller.Net
|
||||
}
|
||||
}
|
||||
|
||||
protected void SendData(bool force)
|
||||
protected async Task SendData(bool force)
|
||||
{
|
||||
Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>[] tuples;
|
||||
|
||||
@@ -128,13 +128,18 @@ namespace MediaBrowser.Controller.Net
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
foreach (var tuple in tuples)
|
||||
IEnumerable<Task> GetTasks()
|
||||
{
|
||||
SendData(tuple);
|
||||
foreach (var tuple in tuples)
|
||||
{
|
||||
yield return SendData(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(GetTasks()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, TStateType> tuple)
|
||||
private async Task SendData(Tuple<IWebSocketConnection, CancellationTokenSource, TStateType> tuple)
|
||||
{
|
||||
var connection = tuple.Item1;
|
||||
|
||||
@@ -148,11 +153,13 @@ namespace MediaBrowser.Controller.Net
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
await connection.SendAsync(new WebSocketMessage<TReturnDataType>
|
||||
{
|
||||
MessageType = Name,
|
||||
Data = data
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
await connection.SendAsync(
|
||||
new WebSocketMessage<TReturnDataType>
|
||||
{
|
||||
MessageType = Name,
|
||||
Data = data
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
state.DateLastSendUtc = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,12 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <value>The last activity date.</value>
|
||||
DateTime LastActivityDate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date of last Keeplive received.
|
||||
/// </summary>
|
||||
/// <value>The date of last Keeplive received.</value>
|
||||
DateTime LastKeepAliveDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the query string.
|
||||
/// </summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
|
||||
namespace MediaBrowser.Controller.Session
|
||||
{
|
||||
@@ -140,6 +141,24 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <returns>Task.</returns>
|
||||
Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the SyncPlayCommand.
|
||||
/// </summary>
|
||||
/// <param name="sessionId">The session id.</param>
|
||||
/// <param name="command">The command.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendSyncPlayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the SyncPlayGroupUpdate.
|
||||
/// </summary>
|
||||
/// <param name="sessionId">The session id.</param>
|
||||
/// <param name="command">The group update.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendSyncPlayGroupUpdate<T>(string sessionId, GroupUpdate<T> command, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the browse command.
|
||||
/// </summary>
|
||||
|
||||
169
MediaBrowser.Controller/SyncPlay/GroupInfo.cs
Normal file
169
MediaBrowser.Controller/SyncPlay/GroupInfo.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.SyncPlay
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GroupInfo.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Class is not thread-safe, external locking is required when accessing methods.
|
||||
/// </remarks>
|
||||
public class GroupInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Default ping value used for sessions.
|
||||
/// </summary>
|
||||
public long DefaulPing { get; } = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the group identifier.
|
||||
/// </summary>
|
||||
/// <value>The group identifier.</value>
|
||||
public Guid GroupId { get; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playing item.
|
||||
/// </summary>
|
||||
/// <value>The playing item.</value>
|
||||
public BaseItem PlayingItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether playback is paused.
|
||||
/// </summary>
|
||||
/// <value>Playback is paused.</value>
|
||||
public bool IsPaused { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position ticks.
|
||||
/// </summary>
|
||||
/// <value>The position ticks.</value>
|
||||
public long PositionTicks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last activity.
|
||||
/// </summary>
|
||||
/// <value>The last activity.</value>
|
||||
public DateTime LastActivity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the participants.
|
||||
/// </summary>
|
||||
/// <value>The participants, or members of the group.</value>
|
||||
public Dictionary<string, GroupMember> Participants { get; } =
|
||||
new Dictionary<string, GroupMember>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a session is in this group.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the session is in this group; <c>false</c> otherwise.</value>
|
||||
public bool ContainsSession(string sessionId)
|
||||
{
|
||||
return Participants.ContainsKey(sessionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the session to the group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
public void AddSession(SessionInfo session)
|
||||
{
|
||||
if (ContainsSession(session.Id.ToString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var member = new GroupMember();
|
||||
member.Session = session;
|
||||
member.Ping = DefaulPing;
|
||||
member.IsBuffering = false;
|
||||
Participants[session.Id.ToString()] = member;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the session from the group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
public void RemoveSession(SessionInfo session)
|
||||
{
|
||||
if (!ContainsSession(session.Id.ToString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Participants.Remove(session.Id.ToString(), out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the ping of a session.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="ping">The ping.</param>
|
||||
public void UpdatePing(SessionInfo session, long ping)
|
||||
{
|
||||
if (!ContainsSession(session.Id.ToString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Participants[session.Id.ToString()].Ping = ping;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the highest ping in the group.
|
||||
/// </summary>
|
||||
/// <value name="session">The highest ping in the group.</value>
|
||||
public long GetHighestPing()
|
||||
{
|
||||
long max = Int64.MinValue;
|
||||
foreach (var session in Participants.Values)
|
||||
{
|
||||
max = Math.Max(max, session.Ping);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the session's buffering state.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="isBuffering">The state.</param>
|
||||
public void SetBuffering(SessionInfo session, bool isBuffering)
|
||||
{
|
||||
if (!ContainsSession(session.Id.ToString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Participants[session.Id.ToString()].IsBuffering = isBuffering;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the group buffering state.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if there is a session buffering in the group; <c>false</c> otherwise.</value>
|
||||
public bool IsBuffering()
|
||||
{
|
||||
foreach (var session in Participants.Values)
|
||||
{
|
||||
if (session.IsBuffering)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the group is empty.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the group is empty; <c>false</c> otherwise.</value>
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return Participants.Count == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
MediaBrowser.Controller/SyncPlay/GroupMember.cs
Normal file
28
MediaBrowser.Controller/SyncPlay/GroupMember.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.SyncPlay
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GroupMember.
|
||||
/// </summary>
|
||||
public class GroupMember
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets whether this member is buffering.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if member is buffering; <c>false</c> otherwise.</value>
|
||||
public bool IsBuffering { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the session.
|
||||
/// </summary>
|
||||
/// <value>The session.</value>
|
||||
public SessionInfo Session { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ping.
|
||||
/// </summary>
|
||||
/// <value>The ping.</value>
|
||||
public long Ping { get; set; }
|
||||
}
|
||||
}
|
||||
67
MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs
Normal file
67
MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
|
||||
namespace MediaBrowser.Controller.SyncPlay
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface ISyncPlayController.
|
||||
/// </summary>
|
||||
public interface ISyncPlayController
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the group id.
|
||||
/// </summary>
|
||||
/// <value>The group id.</value>
|
||||
Guid GetGroupId();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the playing item id.
|
||||
/// </summary>
|
||||
/// <value>The playing item id.</value>
|
||||
Guid GetPlayingItemId();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the group is empty.
|
||||
/// </summary>
|
||||
/// <value>If the group is empty.</value>
|
||||
bool IsGroupEmpty();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the group with the session's info.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void InitGroup(SessionInfo session, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the session to the group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the session from the group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void SessionLeave(SessionInfo session, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Handles the requested action by the session.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="request">The requested action.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the info about the group for the clients.
|
||||
/// </summary>
|
||||
/// <value>The group info for the clients.</value>
|
||||
GroupInfoView GetInfo();
|
||||
}
|
||||
}
|
||||
69
MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs
Normal file
69
MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
|
||||
namespace MediaBrowser.Controller.SyncPlay
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface ISyncPlayManager.
|
||||
/// </summary>
|
||||
public interface ISyncPlayManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session that's creating the group.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void NewGroup(SessionInfo session, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the session to a group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void JoinGroup(SessionInfo session, Guid groupId, JoinGroupRequest request, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the session from a group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void LeaveGroup(SessionInfo session, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets list of available groups for a session.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="filterItemId">The item id to filter by.</param>
|
||||
/// <value>The list of available groups.</value>
|
||||
List<GroupInfoView> ListGroups(SessionInfo session, Guid filterItemId);
|
||||
|
||||
/// <summary>
|
||||
/// Handle a request by a session in a group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a session to a group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="group">The group.</param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
void AddSessionToGroup(SessionInfo session, ISyncPlayController group);
|
||||
|
||||
/// <summary>
|
||||
/// Unmaps a session from a group.
|
||||
/// </summary>
|
||||
/// <param name="session">The session.</param>
|
||||
/// <param name="group">The group.</param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
void RemoveSessionFromGroup(SessionInfo session, ISyncPlayController group);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user