aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS.md2
-rw-r--r--Dockerfile11
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/DynamicImageProvider.cs10
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-US.json4
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs7
-rw-r--r--Jellyfin.Api/Controllers/DisplayPreferencesController.cs6
-rw-r--r--Jellyfin.Api/Controllers/PluginsController.cs71
-rw-r--r--Jellyfin.Api/Helpers/TranscodingJobHelper.cs16
-rw-r--r--Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs40
-rw-r--r--Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs12
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs38
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs6
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs6
-rw-r--r--MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs124
-rw-r--r--MediaBrowser.MediaEncoding/Probing/MediaChapter.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs4
-rw-r--r--src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs4
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj2
-rw-r--r--tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj2
-rw-r--r--tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj2
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj2
-rw-r--r--tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj2
-rw-r--r--tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj2
-rw-r--r--tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj2
-rw-r--r--tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj2
-rw-r--r--tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj2
30 files changed, 236 insertions, 169 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 86a8ecc82..76b3c1dcb 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -45,6 +45,7 @@
- [Froghut](https://github.com/Froghut)
- [fruhnow](https://github.com/fruhnow)
- [geilername](https://github.com/geilername)
+ - [GermanCoding](https://github.com/GermanCoding)
- [gnattu](https://github.com/gnattu)
- [GodTamIt](https://github.com/GodTamIt)
- [grafixeyehero](https://github.com/grafixeyehero)
@@ -76,6 +77,7 @@
- [mitchfizz05](https://github.com/mitchfizz05)
- [MrTimscampi](https://github.com/MrTimscampi)
- [n8225](https://github.com/n8225)
+ - [Nalsai](https://github.com/Nalsai)
- [Narfinger](https://github.com/Narfinger)
- [NathanPickard](https://github.com/NathanPickard)
- [neilsb](https://github.com/neilsb)
diff --git a/Dockerfile b/Dockerfile
index f0090889f..c3038b1d2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,10 +22,10 @@ ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
# https://github.com/intel/compute-runtime/releases
-ARG GMMLIB_VERSION=21.2.1
-ARG IGC_VERSION=1.0.8517
-ARG NEO_VERSION=21.35.20826
-ARG LEVEL_ZERO_VERSION=1.2.20826
+ARG GMMLIB_VERSION=22.0.2
+ARG IGC_VERSION=1.0.10395
+ARG NEO_VERSION=22.08.22549
+ARG LEVEL_ZERO_VERSION=1.3.22549
# Install dependencies:
# mesa-va-drivers: needed for AMD VAAPI. Mesa >= 20.1 is required for HEVC transcoding.
@@ -48,8 +48,7 @@ RUN apt-get update \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-gmmlib_${GMMLIB_VERSION}_amd64.deb \
&& wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-core_${IGC_VERSION}_amd64.deb \
&& wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-opencl_${IGC_VERSION}_amd64.deb \
- && wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl_${NEO_VERSION}_amd64.deb \
- && wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-ocloc_${NEO_VERSION}_amd64.deb \
+ && wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl-icd_${NEO_VERSION}_amd64.deb \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-level-zero-gpu_${LEVEL_ZERO_VERSION}_amd64.deb \
&& dpkg -i *.deb \
&& cd .. \
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 758986945..57c2f1a5e 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -135,7 +135,7 @@ namespace Emby.Server.Implementations.Images
protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> items)
{
- var useBackdrop = primaryItem is CollectionFolder;
+ var useBackdrop = primaryItem is CollectionFolder || primaryItem is UserView;
return items
.Select(i =>
{
diff --git a/Emby.Server.Implementations/Images/DynamicImageProvider.cs b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
index 575680653..9f9a4902a 100644
--- a/Emby.Server.Implementations/Images/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
@@ -84,16 +84,20 @@ namespace Emby.Server.Implementations.Images
}).GroupBy(x => x.Id)
.Select(x => x.First());
+ List<BaseItem> returnItems;
if (isUsingCollectionStrip)
{
- return items
+ returnItems = items
.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb))
.ToList();
+ returnItems.Shuffle();
+ return returnItems;
}
-
- return items
+ returnItems = items
.Where(i => i.HasImage(ImageType.Primary))
.ToList();
+ returnItems.Shuffle();
+ return returnItems;
}
protected override bool Supports(BaseItem item)
diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json
index 568a8e447..e06f8e6fe 100644
--- a/Emby.Server.Implementations/Localization/Core/en-US.json
+++ b/Emby.Server.Implementations/Localization/Core/en-US.json
@@ -119,5 +119,7 @@
"TaskDownloadMissingSubtitles": "Download missing subtitles",
"TaskDownloadMissingSubtitlesDescription": "Searches the internet for missing subtitles based on metadata configuration.",
"TaskOptimizeDatabase": "Optimize database",
- "TaskOptimizeDatabaseDescription": "Compacts database and truncates free space. Running this task after scanning the library or doing other changes that imply database modifications might improve performance."
+ "TaskOptimizeDatabaseDescription": "Compacts database and truncates free space. Running this task after scanning the library or doing other changes that imply database modifications might improve performance.",
+ "TaskKeyframeExtractor": "Keyframe Extractor",
+ "TaskKeyframeExtractorDescription": "Extracts keyframes from video files to create more precise HLS playlists. This task may run for a long time."
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 6c679ea20..ab860ef67 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -424,9 +424,14 @@ namespace Emby.Server.Implementations.Session
var nowPlayingQueue = info.NowPlayingQueue;
- if (nowPlayingQueue != null)
+ if (nowPlayingQueue?.Length > 0)
{
session.NowPlayingQueue = nowPlayingQueue;
+
+ var itemIds = nowPlayingQueue.Select(queue => queue.Id).ToArray();
+ session.NowPlayingQueueFullItems = _dtoService.GetBaseItemDtos(
+ _libraryManager.GetItemList(new InternalItemsQuery { ItemIds = itemIds }),
+ new DtoOptions(true));
}
}
diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index 0b2604640..27eb22339 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -126,9 +126,11 @@ namespace Jellyfin.Api.Controllers
HomeSectionType.SmallLibraryTiles,
HomeSectionType.Resume,
HomeSectionType.ResumeAudio,
+ HomeSectionType.ResumeBook,
HomeSectionType.LiveTv,
HomeSectionType.NextUp,
- HomeSectionType.LatestMedia, HomeSectionType.None,
+ HomeSectionType.LatestMedia,
+ HomeSectionType.None,
};
if (!Guid.TryParse(displayPreferencesId, out var itemId))
@@ -182,7 +184,7 @@ namespace Jellyfin.Api.Controllers
var order = int.Parse(key.AsSpan().Slice("homesection".Length));
if (!Enum.TryParse<HomeSectionType>(displayPreferences.CustomPrefs[key], true, out var type))
{
- type = order < 7 ? defaults[order] : HomeSectionType.None;
+ type = order < 8 ? defaults[order] : HomeSectionType.None;
}
displayPreferences.CustomPrefs.Remove(key);
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index b41df1abb..b227dba2d 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -7,7 +7,6 @@ using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
-using Jellyfin.Api.Models.PluginDtos;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
@@ -44,61 +43,6 @@ namespace Jellyfin.Api.Controllers
}
/// <summary>
- /// Get plugin security info.
- /// </summary>
- /// <response code="200">Plugin security info returned.</response>
- /// <returns>Plugin security info.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpGet("SecurityInfo")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public static ActionResult<PluginSecurityInfo> GetPluginSecurityInfo()
- {
- return new PluginSecurityInfo
- {
- IsMbSupporter = true,
- SupporterKey = "IAmTotallyLegit"
- };
- }
-
- /// <summary>
- /// Gets registration status for a feature.
- /// </summary>
- /// <param name="name">Feature name.</param>
- /// <response code="200">Registration status returned.</response>
- /// <returns>Mb registration record.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpPost("RegistrationRecords/{name}")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public static ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute, Required] string name)
- {
- return new MBRegistrationRecord
- {
- IsRegistered = true,
- RegChecked = true,
- TrialVersion = false,
- IsValid = true,
- RegError = false
- };
- }
-
- /// <summary>
- /// Gets registration status for a feature.
- /// </summary>
- /// <param name="name">Feature name.</param>
- /// <response code="501">Not implemented.</response>
- /// <returns>Not Implemented.</returns>
- /// <exception cref="NotImplementedException">This endpoint is not implemented.</exception>
- [Obsolete("Paid plugins are not supported")]
- [HttpGet("Registrations/{name}")]
- [ProducesResponseType(StatusCodes.Status501NotImplemented)]
- public static ActionResult GetRegistration([FromRoute, Required] string name)
- {
- // TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,
- // delete all these registration endpoints. They are only kept for compatibility.
- throw new NotImplementedException();
- }
-
- /// <summary>
/// Gets a list of currently installed plugins.
/// </summary>
/// <response code="200">Installed plugins returned.</response>
@@ -317,20 +261,5 @@ namespace Jellyfin.Api.Controllers
return NotFound();
}
-
- /// <summary>
- /// Updates plugin security info.
- /// </summary>
- /// <param name="pluginSecurityInfo">Plugin security info.</param>
- /// <response code="204">Plugin security info updated.</response>
- /// <returns>An <see cref="NoContentResult"/>.</returns>
- [Obsolete("This endpoint should not be used.")]
- [HttpPost("SecurityInfo")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- public ActionResult UpdatePluginSecurityInfo([FromBody, Required] PluginSecurityInfo pluginSecurityInfo)
- {
- return NoContent();
- }
}
}
diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
index 56a54fb1d..e70b79837 100644
--- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
+++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
@@ -42,6 +43,8 @@ namespace Jellyfin.Api.Helpers
/// </summary>
private static readonly Dictionary<string, SemaphoreSlim> _transcodingLocks = new Dictionary<string, SemaphoreSlim>();
+ private readonly IAttachmentExtractor _attachmentExtractor;
+ private readonly IApplicationPaths _appPaths;
private readonly IAuthorizationContext _authorizationContext;
private readonly EncodingHelper _encodingHelper;
private readonly IFileSystem _fileSystem;
@@ -55,6 +58,8 @@ namespace Jellyfin.Api.Helpers
/// <summary>
/// Initializes a new instance of the <see cref="TranscodingJobHelper"/> class.
/// </summary>
+ /// <param name="attachmentExtractor">Instance of the <see cref="IAttachmentExtractor"/> interface.</param>
+ /// <param name="appPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{TranscodingJobHelpers}"/> interface.</param>
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
@@ -65,6 +70,8 @@ namespace Jellyfin.Api.Helpers
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
public TranscodingJobHelper(
+ IAttachmentExtractor attachmentExtractor,
+ IApplicationPaths appPaths,
ILogger<TranscodingJobHelper> logger,
IMediaSourceManager mediaSourceManager,
IFileSystem fileSystem,
@@ -75,6 +82,8 @@ namespace Jellyfin.Api.Helpers
EncodingHelper encodingHelper,
ILoggerFactory loggerFactory)
{
+ _attachmentExtractor = attachmentExtractor;
+ _appPaths = appPaths;
_logger = logger;
_mediaSourceManager = mediaSourceManager;
_fileSystem = fileSystem;
@@ -513,6 +522,13 @@ namespace Jellyfin.Api.Helpers
throw new ArgumentException("FFmpeg path not set.");
}
+ // If subtitles get burned in fonts may need to be extracted from the media file
+ if (state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
+ {
+ var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id);
+ await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, CancellationToken.None).ConfigureAwait(false);
+ }
+
var process = new Process
{
StartInfo = new ProcessStartInfo
diff --git a/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs b/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs
deleted file mode 100644
index 7f1255f4b..000000000
--- a/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-
-namespace Jellyfin.Api.Models.PluginDtos
-{
- /// <summary>
- /// MB Registration Record.
- /// </summary>
- public class MBRegistrationRecord
- {
- /// <summary>
- /// Gets or sets expiration date.
- /// </summary>
- public DateTime ExpirationDate { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether is registered.
- /// </summary>
- public bool IsRegistered { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether reg checked.
- /// </summary>
- public bool RegChecked { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether reg error.
- /// </summary>
- public bool RegError { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether trial version.
- /// </summary>
- public bool TrialVersion { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether is valid.
- /// </summary>
- public bool IsValid { get; set; }
- }
-}
diff --git a/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs b/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs
deleted file mode 100644
index a90398425..000000000
--- a/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Jellyfin.Api.Models.PluginDtos
-{
- /// <summary>
- /// Plugin security info.
- /// </summary>
- public class PluginSecurityInfo
- {
- /// <summary>
- /// Gets or sets the supporter key.
- /// </summary>
- public string? SupporterKey { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether is mb supporter.
- /// </summary>
- public bool IsMbSupporter { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 4d9aac6f9..cb5ff6eec 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -848,6 +848,18 @@ namespace MediaBrowser.Controller.Entities
return true;
}
+ if (query.HasThemeSong.HasValue)
+ {
+ Logger.LogDebug("Query requires post-filtering due to HasThemeSong");
+ return true;
+ }
+
+ if (query.HasThemeVideo.HasValue)
+ {
+ Logger.LogDebug("Query requires post-filtering due to HasThemeVideo");
+ return true;
+ }
+
// Filter by VideoType
if (query.VideoTypes.Length > 0)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index cdfde97f6..931337bf4 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -12,6 +12,7 @@ using System.Text.RegularExpressions;
using System.Threading;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
@@ -28,7 +29,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private const string VideotoolboxAlias = "vt";
private const string OpenclAlias = "ocl";
private const string CudaAlias = "cu";
-
+ private readonly IApplicationPaths _appPaths;
private readonly IMediaEncoder _mediaEncoder;
private readonly ISubtitleEncoder _subtitleEncoder;
@@ -51,9 +52,11 @@ namespace MediaBrowser.Controller.MediaEncoding
};
public EncodingHelper(
+ IApplicationPaths appPaths,
IMediaEncoder mediaEncoder,
ISubtitleEncoder subtitleEncoder)
{
+ _appPaths = appPaths;
_mediaEncoder = mediaEncoder;
_subtitleEncoder = subtitleEncoder;
}
@@ -1080,6 +1083,12 @@ namespace MediaBrowser.Controller.MediaEncoding
var alphaParam = enableAlpha ? ":alpha=1" : string.Empty;
var sub2videoParam = enableSub2video ? ":sub2video=1" : string.Empty;
+ var fontPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id);
+ var fontParam = string.Format(
+ CultureInfo.InvariantCulture,
+ ":fontsdir={0}",
+ _mediaEncoder.EscapeSubtitleFilterPath(fontPath));
+
// TODO
// var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf");
// string fallbackFontParam = string.Empty;
@@ -1120,11 +1129,12 @@ namespace MediaBrowser.Controller.MediaEncoding
// TODO: Perhaps also use original_size=1920x800 ??
return string.Format(
CultureInfo.InvariantCulture,
- "subtitles=f='{0}'{1}{2}{3}{4}",
+ "subtitles=f='{0}'{1}{2}{3}{4}{5}",
_mediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
charsetParam,
alphaParam,
sub2videoParam,
+ fontParam,
// fallbackFontParam,
setPtsParam);
}
@@ -1133,11 +1143,12 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format(
CultureInfo.InvariantCulture,
- "subtitles='{0}:si={1}{2}{3}'{4}",
+ "subtitles='{0}:si={1}{2}{3}{4}'{5}",
_mediaEncoder.EscapeSubtitleFilterPath(mediaPath),
state.InternalSubtitleStreamOffset.ToString(CultureInfo.InvariantCulture),
alphaParam,
sub2videoParam,
+ fontParam,
// fallbackFontParam,
setPtsParam);
}
@@ -1338,29 +1349,37 @@ namespace MediaBrowser.Controller.MediaEncoding
switch (encodingOptions.EncoderPreset)
{
case "veryslow":
-
- param += " -preset slow"; // lossless is only supported on maxwell and newer(2014+)
+ param += " -preset p7";
break;
case "slow":
+ param += " -preset p6";
+ break;
+
case "slower":
- param += " -preset slow";
+ param += " -preset p5";
break;
case "medium":
- param += " -preset medium";
+ param += " -preset p4";
break;
case "fast":
+ param += " -preset p3";
+ break;
+
case "faster":
+ param += " -preset p2";
+ break;
+
case "veryfast":
case "superfast":
case "ultrafast":
- param += " -preset fast";
+ param += " -preset p1";
break;
default:
- param += " -preset default";
+ param += " -preset p4";
break;
}
}
@@ -2162,6 +2181,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase)
&& state.TranscodingType != TranscodingJobType.Progressive
+ && state.TranscodingType != TranscodingJobType.Hls
&& !state.EnableBreakOnNonKeyFrames(outputVideoCodec)
&& (state.BaseRequest.StartTimeTicks ?? 0) > 0)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
index 4e7e26624..a2b6be1e6 100644
--- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.MediaEncoding
@@ -17,5 +18,10 @@ namespace MediaBrowser.Controller.MediaEncoding
string mediaSourceId,
int attachmentStreamIndex,
CancellationToken cancellationToken);
+ Task ExtractAllAttachments(
+ string inputFile,
+ MediaSourceInfo mediaSource,
+ string outputPath,
+ CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 6134c0cf3..c2ca23386 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -39,6 +39,8 @@ namespace MediaBrowser.Controller.Session
AdditionalUsers = Array.Empty<SessionUserInfo>();
PlayState = new PlayerStateInfo();
SessionControllers = Array.Empty<ISessionController>();
+ NowPlayingQueue = Array.Empty<QueueItem>();
+ NowPlayingQueueFullItems = Array.Empty<BaseItemDto>();
}
public PlayerStateInfo PlayState { get; set; }
@@ -219,7 +221,9 @@ namespace MediaBrowser.Controller.Session
}
}
- public QueueItem[] NowPlayingQueue { get; set; }
+ public IReadOnlyList<QueueItem> NowPlayingQueue { get; set; }
+
+ public IReadOnlyList<BaseItemDto> NowPlayingQueueFullItems { get; set; }
public bool HasCustomDeviceName { get; set; }
diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
index 3fd4cd731..06d20d90e 100644
--- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
+++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
@@ -83,6 +83,130 @@ namespace MediaBrowser.MediaEncoding.Attachments
return (mediaAttachment, attachmentStream);
}
+ public async Task ExtractAllAttachments(
+ string inputFile,
+ MediaSourceInfo mediaSource,
+ string outputPath,
+ CancellationToken cancellationToken)
+ {
+ var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1));
+
+ await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ if (!Directory.Exists(outputPath))
+ {
+ await ExtractAllAttachmentsInternal(
+ _mediaEncoder.GetInputArgument(inputFile, mediaSource),
+ outputPath,
+ cancellationToken).ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ }
+
+ private async Task ExtractAllAttachmentsInternal(
+ string inputPath,
+ string outputPath,
+ CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrEmpty(inputPath))
+ {
+ throw new ArgumentNullException(nameof(inputPath));
+ }
+
+ if (string.IsNullOrEmpty(outputPath))
+ {
+ throw new ArgumentNullException(nameof(outputPath));
+ }
+
+ Directory.CreateDirectory(outputPath);
+
+ var processArgs = string.Format(
+ CultureInfo.InvariantCulture,
+ "-dump_attachment:t \"\" -i {0} -t 0 -f null null",
+ inputPath);
+
+ int exitCode;
+
+ using (var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ Arguments = processArgs,
+ FileName = _mediaEncoder.EncoderPath,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ WorkingDirectory = outputPath,
+ ErrorDialog = false
+ },
+ EnableRaisingEvents = true
+ })
+ {
+ _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
+
+ process.Start();
+
+ var ranToCompletion = await ProcessExtensions.WaitForExitAsync(process, cancellationToken).ConfigureAwait(false);
+
+ if (!ranToCompletion)
+ {
+ try
+ {
+ _logger.LogWarning("Killing ffmpeg attachment extraction process");
+ process.Kill();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error killing attachment extraction process");
+ }
+ }
+
+ exitCode = ranToCompletion ? process.ExitCode : -1;
+ }
+
+ var failed = false;
+
+ if (exitCode != 0)
+ {
+ failed = true;
+
+ _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputPath, exitCode);
+ try
+ {
+ if (Directory.Exists(outputPath))
+ {
+ Directory.Delete(outputPath);
+ }
+ }
+ catch (IOException ex)
+ {
+ _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputPath);
+ }
+ }
+ else if (!Directory.Exists(outputPath))
+ {
+ failed = true;
+ }
+
+ if (failed)
+ {
+ _logger.LogError("ffmpeg attachment extraction failed for {InputPath} to {OutputPath}", inputPath, outputPath);
+
+ throw new InvalidOperationException(
+ string.Format(CultureInfo.InvariantCulture, "ffmpeg attachment extraction failed for {0} to {1}", inputPath, outputPath));
+ }
+ else
+ {
+ _logger.LogInformation("ffmpeg attachment extraction completed for {Path} to {Path}", inputPath, outputPath);
+ }
+ }
+
private async Task<Stream> GetAttachmentStream(
MediaSourceInfo mediaSource,
MediaAttachment mediaAttachment,
diff --git a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs
index a1cef7a9f..c9e948780 100644
--- a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs
+++ b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.MediaEncoding.Probing
public class MediaChapter
{
[JsonPropertyName("id")]
- public int Id { get; set; }
+ public long Id { get; set; }
[JsonPropertyName("time_base")]
public string TimeBase { get; set; }
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 4c8f19604..8313ab5bc 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -691,9 +691,9 @@ namespace MediaBrowser.MediaEncoding.Probing
if (string.IsNullOrEmpty(stream.Title))
{
- // mp4 missing track title workaround: fall back to handler_name if populated
+ // mp4 missing track title workaround: fall back to handler_name if populated and not the default "SoundHandler"
string handlerName = GetDictionaryValue(streamInfo.Tags, "handler_name");
- if (!string.IsNullOrEmpty(handlerName))
+ if (!string.IsNullOrEmpty(handlerName) && !string.Equals(handlerName, "SoundHandler", StringComparison.OrdinalIgnoreCase))
{
stream.Title = handlerName;
}
diff --git a/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs b/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs
index d80925fc9..a7d52184b 100644
--- a/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs
+++ b/src/Jellyfin.MediaEncoding.Hls/ScheduledTasks/KeyframeExtractionScheduledTask.cs
@@ -39,13 +39,13 @@ public class KeyframeExtractionScheduledTask : IScheduledTask
}
/// <inheritdoc />
- public string Name => "Keyframe Extractor";
+ public string Name => _localizationManager.GetLocalizedString("TaskKeyframeExtractor");
/// <inheritdoc />
public string Key => "KeyframeExtraction";
/// <inheritdoc />
- public string Description => "Extracts keyframes from video files to create more precise HLS playlists. This task may run for a long time.";
+ public string Description => _localizationManager.GetLocalizedString("TaskKeyframeExtractorDescription");
/// <inheritdoc />
public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory");
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index e04bfffbb..e3237a8e3 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -21,7 +21,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index f7f9c0361..abe7bee64 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
index a9935bbdb..cb1536274 100644
--- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
+++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
@@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index 7a1d88ca6..7803e49e1 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -23,7 +23,7 @@
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
</ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index cc3d4faa0..929764e42 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
index 00aac8965..5c3c39bf6 100644
--- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
+++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj
@@ -17,7 +17,7 @@
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.4" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
</ItemGroup>
<!-- Code Analyzers-->
diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
index 5531049f5..59c737c7d 100644
--- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
+++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
@@ -14,7 +14,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index 066112dcb..fb8593345 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -22,7 +22,7 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
index 43e38ea6e..0af39affa 100644
--- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
+++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Xunit.Priority" Version="1.1.6" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
</ItemGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
index 9576f6a11..bc829d0a1 100644
--- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
+++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj
@@ -16,7 +16,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
</ItemGroup>
<!-- Code Analyzers -->
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
index f34dbc922..c4469d10a 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
@@ -14,7 +14,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
- <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="Moq" Version="4.17.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />