aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile23
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs24
-rw-r--r--Emby.Dlna/Properties/AssemblyInfo.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthService.cs9
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs85
-rw-r--r--Emby.Server.Implementations/Localization/Core/el.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/ro.json5
-rw-r--r--Emby.Server.Implementations/MediaEncoder/EncodingManager.cs20
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs14
-rw-r--r--Jellyfin.Api/Auth/CustomAuthenticationHandler.cs5
-rw-r--r--Jellyfin.Api/Helpers/TranscodingJobHelper.cs5
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDb.cs2
-rw-r--r--Jellyfin.Server.Implementations/ModelBuilderExtensions.cs48
-rw-r--r--Jellyfin.Server.Implementations/ValueConverters/DateTimeKindValueConverter.cs21
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs27
-rw-r--r--Jellyfin.Server/Startup.cs2
-rw-r--r--MediaBrowser.Common/Json/Converters/JsonDateTimeIso8601Converter.cs24
-rw-r--r--MediaBrowser.Common/Json/JsonDefaults.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs45
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs56
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs5
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs15
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs33
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs11
-rw-r--r--MediaBrowser.Controller/Net/AuthorizationInfo.cs5
-rw-r--r--MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs16
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs29
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs71
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs55
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs4
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs26
-rw-r--r--MediaBrowser.sln9
-rw-r--r--tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs4
-rw-r--r--tests/Jellyfin.Dlna.Tests/GetUuidTests.cs17
-rw-r--r--tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj33
38 files changed, 368 insertions, 396 deletions
diff --git a/Dockerfile b/Dockerfile
index 963027b49..41dd3d081 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,8 +27,15 @@ ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
COPY --from=builder /jellyfin /jellyfin
COPY --from=web-builder /dist /jellyfin/jellyfin-web
+
+# https://github.com/intel/compute-runtime/releases
+ARG GMMLIB_VERSION=20.3.2
+ARG IGC_VERSION=1.0.5435
+ARG NEO_VERSION=20.46.18421
+ARG LEVEL_ZERO_VERSION=1.0.18421
+
# Install dependencies:
-# mesa-va-drivers: needed for AMD VAAPI
+# mesa-va-drivers: needed for AMD VAAPI. Mesa >= 20.1 is required for HEVC transcoding.
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg wget apt-transport-https \
&& wget -O - https://repo.jellyfin.org/jellyfin_team.gpg.key | apt-key add - \
@@ -39,6 +46,20 @@ RUN apt-get update \
jellyfin-ffmpeg \
openssl \
locales \
+# Intel VAAPI Tone mapping dependencies:
+# Prefer NEO to Beignet since the latter one doesn't support Comet Lake or newer for now.
+# Do not use the intel-opencl-icd package from repo since they will not build with RELEASE_WITH_REGKEYS enabled.
+ && mkdir intel-compute-runtime \
+ && cd intel-compute-runtime \
+ && 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-level-zero-gpu_${LEVEL_ZERO_VERSION}_amd64.deb \
+ && dpkg -i *.deb \
+ && cd .. \
+ && rm -rf intel-compute-runtime \
&& apt-get remove gnupg wget apt-transport-https -y \
&& apt-get clean autoclean -y \
&& apt-get autoremove -y \
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 854b6a1a2..cb183ce71 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -3,13 +3,11 @@
using System;
using System.Globalization;
using System.Linq;
-using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Events;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
@@ -130,24 +128,36 @@ namespace Emby.Dlna.PlayTo
}
}
- private static string GetUuid(string usn)
+ internal static string GetUuid(string usn)
{
const string UuidStr = "uuid:";
const string UuidColonStr = "::";
var index = usn.IndexOf(UuidStr, StringComparison.OrdinalIgnoreCase);
+ if (index == -1)
+ {
+ return usn.GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ }
+
+ ReadOnlySpan<char> tmp = usn.AsSpan()[(index + UuidStr.Length)..];
+
+ index = tmp.IndexOf(UuidColonStr, StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
- return usn.Substring(index + UuidStr.Length);
+ tmp = tmp[..index];
}
- index = usn.IndexOf(UuidColonStr, StringComparison.OrdinalIgnoreCase);
+ index = tmp.IndexOf('{');
if (index != -1)
{
- usn = usn.Substring(0, index + UuidColonStr.Length);
+ int endIndex = tmp.IndexOf('}');
+ if (endIndex != -1)
+ {
+ tmp = tmp[(index + 1)..endIndex];
+ }
}
- return usn.GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ return tmp.ToString();
}
private async Task AddDevice(UpnpDeviceInfo info, string location, CancellationToken cancellationToken)
diff --git a/Emby.Dlna/Properties/AssemblyInfo.cs b/Emby.Dlna/Properties/AssemblyInfo.cs
index a2c1e0db8..606ffcf4f 100644
--- a/Emby.Dlna/Properties/AssemblyInfo.cs
+++ b/Emby.Dlna/Properties/AssemblyInfo.cs
@@ -1,5 +1,6 @@
using System.Reflection;
using System.Resources;
+using System.Runtime.CompilerServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
@@ -13,6 +14,7 @@ using System.Resources;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
+[assembly: InternalsVisibleTo("Jellyfin.Dlna.Tests")]
// Version information for an assembly consists of the following four values:
//
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
index df7a034e8..4a0fc8239 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Net;
@@ -20,9 +21,15 @@ namespace Emby.Server.Implementations.HttpServer.Security
public AuthorizationInfo Authenticate(HttpRequest request)
{
var auth = _authorizationContext.GetAuthorizationInfo(request);
+
+ if (!auth.HasToken)
+ {
+ throw new AuthenticationException("Request does not contain a token.");
+ }
+
if (!auth.IsAuthenticated)
{
- throw new AuthenticationException("Invalid token.");
+ throw new SecurityException("Invalid token.");
}
if (auth.User?.HasPermission(PermissionKind.IsDisabled) ?? false)
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index fdf2e3908..d62e2eefe 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -102,7 +102,8 @@ namespace Emby.Server.Implementations.HttpServer.Security
DeviceId = deviceId,
Version = version,
Token = token,
- IsAuthenticated = false
+ IsAuthenticated = false,
+ HasToken = false
};
if (string.IsNullOrWhiteSpace(token))
@@ -111,6 +112,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
return authInfo;
}
+ authInfo.HasToken = true;
var result = _authRepo.Get(new AuthenticationInfoQuery
{
AccessToken = token
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index f181eb7a0..1084ddf74 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -4,7 +4,6 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
-using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -19,7 +18,6 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
@@ -36,6 +34,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly IApplicationHost _appHost;
private readonly ICryptoProvider _cryptoProvider;
+ private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
+ private DateTime _lastErrorResponse;
+
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
IJsonSerializer jsonSerializer,
@@ -50,8 +51,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_cryptoProvider = cryptoProvider;
}
- private string UserAgent => _appHost.ApplicationUserAgent;
-
/// <inheritdoc />
public string Name => "Schedules Direct";
@@ -307,7 +306,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (details.contentRating != null && details.contentRating.Count > 0)
{
- info.OfficialRating = details.contentRating[0].code.Replace("TV", "TV-").Replace("--", "-");
+ info.OfficialRating = details.contentRating[0].code.Replace("TV", "TV-", StringComparison.Ordinal)
+ .Replace("--", "-", StringComparison.Ordinal);
var invalid = new[] { "N/A", "Approved", "Not Rated", "Passed" };
if (invalid.Contains(info.OfficialRating, StringComparer.OrdinalIgnoreCase))
@@ -450,7 +450,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
ListingsProviderInfo info,
- List<string> programIds,
+ IReadOnlyList<string> programIds,
CancellationToken cancellationToken)
{
if (programIds.Count == 0)
@@ -458,23 +458,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return new List<ScheduleDirect.ShowImages>();
}
- var imageIdString = "[";
-
- foreach (var i in programIds)
+ StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13));
+ foreach (ReadOnlySpan<char> i in programIds)
{
- var imageId = i.Substring(0, 10);
-
- if (!imageIdString.Contains(imageId, StringComparison.Ordinal))
- {
- imageIdString += "\"" + imageId + "\",";
- }
+ str.Append('"')
+ .Append(i.Slice(0, 10))
+ .Append("\",");
}
- imageIdString = imageIdString.TrimEnd(',') + "]";
+ // Remove last ,
+ str.Length--;
+ str.Append(']');
using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs")
{
- Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json)
+ Content = new StringContent(str.ToString(), Encoding.UTF8, MediaTypeNames.Application.Json)
};
try
@@ -539,9 +537,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return lineups;
}
- private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
- private DateTime _lastErrorResponse;
-
private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken)
{
var username = info.Username;
@@ -564,8 +559,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return null;
}
- NameValuePair savedToken;
- if (!_tokens.TryGetValue(username, out savedToken))
+ if (!_tokens.TryGetValue(username, out NameValuePair savedToken))
{
savedToken = new NameValuePair();
_tokens.TryAdd(username, savedToken);
@@ -655,7 +649,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false);
- if (root.message == "OK")
+ if (string.Equals(root.message, "OK", StringComparison.Ordinal))
{
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
return root.token;
@@ -779,24 +773,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
options.Headers.TryAddWithoutValidation("token", token);
- var list = new List<ChannelInfo>();
-
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(stream).ConfigureAwait(false);
_logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
_logger.LogInformation("Mapping Stations to Channel");
- var allStations = root.stations ?? Enumerable.Empty<ScheduleDirect.Station>();
+ var allStations = root.stations ?? new List<ScheduleDirect.Station>();
- foreach (ScheduleDirect.Map map in root.map)
+ var map = root.map;
+ int len = map.Count;
+ var array = new List<ChannelInfo>(len);
+ for (int i = 0; i < len; i++)
{
- var channelNumber = GetChannelNumber(map);
+ var channelNumber = GetChannelNumber(map[i]);
- var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
+ var station = allStations.Find(item => string.Equals(item.stationID, map[i].stationID, StringComparison.OrdinalIgnoreCase));
if (station == null)
{
- station = new ScheduleDirect.Station { stationID = map.stationID };
+ station = new ScheduleDirect.Station
+ {
+ stationID = map[i].stationID
+ };
}
var channelInfo = new ChannelInfo
@@ -812,32 +810,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
channelInfo.ImageUrl = station.logo.URL;
}
- list.Add(channelInfo);
- }
-
- return list;
- }
-
- private ScheduleDirect.Station GetStation(List<ScheduleDirect.Station> allStations, string channelNumber, string channelName)
- {
- if (!string.IsNullOrWhiteSpace(channelName))
- {
- channelName = NormalizeName(channelName);
-
- var result = allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.callsign ?? string.Empty), channelName, StringComparison.OrdinalIgnoreCase));
-
- if (result != null)
- {
- return result;
- }
- }
-
- if (!string.IsNullOrWhiteSpace(channelNumber))
- {
- return allStations.FirstOrDefault(i => string.Equals(NormalizeName(i.stationID ?? string.Empty), channelNumber, StringComparison.OrdinalIgnoreCase));
+ array[i] = channelInfo;
}
- return null;
+ return array;
}
private static string NormalizeName(string value)
@@ -1046,7 +1022,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- //
public class Title
{
public string title120 { get; set; }
diff --git a/Emby.Server.Implementations/Localization/Core/el.json b/Emby.Server.Implementations/Localization/Core/el.json
index dcf3311cd..23d45b473 100644
--- a/Emby.Server.Implementations/Localization/Core/el.json
+++ b/Emby.Server.Implementations/Localization/Core/el.json
@@ -114,7 +114,7 @@
"TaskUpdatePluginsDescription": "Κατεβάζει και εγκαθιστά ενημερώσεις για τις προσθήκες που έχουν ρυθμιστεί για αυτόματη ενημέρωση.",
"TaskUpdatePlugins": "Ενημέρωση Προσθηκών",
"TaskRefreshPeopleDescription": "Ενημερώνει μεταδεδομένα για ηθοποιούς και σκηνοθέτες στην βιβλιοθήκη των πολυμέσων σας.",
- "TaskCleanActivityLogDescription": "Διαγράφει καταχωρήσεις απο το αρχείο καταγραφής δραστηριοτήτων παλαιότερες από την ηλικία που έχει διαμορφωθεί.",
+ "TaskCleanActivityLogDescription": "Διαγράφει καταχωρήσεις απο το αρχείο καταγραφής παλαιότερες από την επιλεγμένη ηλικία.",
"TaskCleanActivityLog": "Καθαρό Αρχείο Καταγραφής Δραστηριοτήτων",
"Undefined": "Απροσδιόριστο",
"Forced": "Εξαναγκασμένο",
diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json
index 5e4022292..510aac11c 100644
--- a/Emby.Server.Implementations/Localization/Core/ro.json
+++ b/Emby.Server.Implementations/Localization/Core/ro.json
@@ -114,5 +114,8 @@
"TasksLibraryCategory": "Librărie",
"TasksMaintenanceCategory": "Mentenanță",
"TaskCleanActivityLogDescription": "Șterge intrările din jurnalul de activitate mai vechi de data configurată.",
- "TaskCleanActivityLog": "Curăță Jurnalul de Activitate"
+ "TaskCleanActivityLog": "Curăță Jurnalul de Activitate",
+ "Undefined": "Nedefinit",
+ "Forced": "Forțat",
+ "Default": "Implicit"
}
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index 438bbe24a..f27305cbe 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
@@ -81,12 +82,7 @@ namespace Emby.Server.Implementations.MediaEncoder
return false;
}
- if (video.VideoType == VideoType.Iso)
- {
- return false;
- }
-
- if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
+ if (video.VideoType == VideoType.Dvd)
{
return false;
}
@@ -140,15 +136,19 @@ namespace Emby.Server.Implementations.MediaEncoder
// Add some time for the first chapter to make sure we don't end up with a black image
var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
- var protocol = MediaProtocol.File;
-
- var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, null, Array.Empty<string>());
+ var inputPath = video.Path;
Directory.CreateDirectory(Path.GetDirectoryName(path));
var container = video.Container;
+ var mediaSource = new MediaSourceInfo
+ {
+ VideoType = video.VideoType,
+ IsoType = video.IsoType,
+ Protocol = video.PathProtocol.Value,
+ };
- var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
+ var tempFile = await _encoder.ExtractVideoImage(inputPath, container, mediaSource, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
File.Copy(tempFile, path, true);
try
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index a697c6476..3cfcecbd1 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -192,7 +192,7 @@ namespace Emby.Server.Implementations.TV
Func<Episode> getEpisode = () =>
{
- return _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var nextEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
@@ -205,6 +205,18 @@ namespace Emby.Server.Implementations.TV
MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
}).Cast<Episode>().FirstOrDefault();
+
+ if (nextEpisode != null)
+ {
+ var userData = _userDataManager.GetUserData(user, nextEpisode);
+
+ if (userData.PlaybackPositionTicks > 0)
+ {
+ return null;
+ }
+ }
+
+ return nextEpisode;
};
if (lastWatchedEpisode != null)
diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
index 27a1f61be..c56233794 100644
--- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
+++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
@@ -18,6 +18,7 @@ namespace Jellyfin.Api.Auth
public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IAuthService _authService;
+ private readonly ILogger<CustomAuthenticationHandler> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticationHandler" /> class.
@@ -35,6 +36,7 @@ namespace Jellyfin.Api.Auth
ISystemClock clock) : base(options, logger, encoder, clock)
{
_authService = authService;
+ _logger = logger.CreateLogger<CustomAuthenticationHandler>();
}
/// <inheritdoc />
@@ -70,7 +72,8 @@ namespace Jellyfin.Api.Auth
}
catch (AuthenticationException ex)
{
- return Task.FromResult(AuthenticateResult.Fail(ex));
+ _logger.LogDebug(ex, "Error authenticating with {Handler}", nameof(CustomAuthenticationHandler));
+ return Task.FromResult(AuthenticateResult.NoResult());
}
catch (SecurityException ex)
{
diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
index 99c90c315..bb2265dba 100644
--- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
+++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
@@ -762,11 +762,6 @@ namespace Jellyfin.Api.Helpers
private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
{
- if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && _isoManager.CanMount(state.MediaPath))
- {
- state.IsoMount = await _isoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
- }
-
if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId))
{
var liveStreamResponse = await _mediaSourceManager.OpenLiveStream(
diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs
index 45e71f16e..bf8818f8d 100644
--- a/Jellyfin.Server.Implementations/JellyfinDb.cs
+++ b/Jellyfin.Server.Implementations/JellyfinDb.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Interfaces;
@@ -140,6 +141,7 @@ namespace Jellyfin.Server.Implementations
/// <inheritdoc />
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
+ modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("jellyfin");
diff --git a/Jellyfin.Server.Implementations/ModelBuilderExtensions.cs b/Jellyfin.Server.Implementations/ModelBuilderExtensions.cs
new file mode 100644
index 000000000..80ad65a42
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelBuilderExtensions.cs
@@ -0,0 +1,48 @@
+using System;
+using Jellyfin.Server.Implementations.ValueConverters;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations
+{
+ /// <summary>
+ /// Model builder extensions.
+ /// </summary>
+ public static class ModelBuilderExtensions
+ {
+ /// <summary>
+ /// Specify value converter for the object type.
+ /// </summary>
+ /// <param name="modelBuilder">The model builder.</param>
+ /// <param name="converter">The <see cref="ValueConverter{TModel,TProvider}"/>.</param>
+ /// <typeparam name="T">The type to convert.</typeparam>
+ /// <returns>The modified <see cref="ModelBuilder"/>.</returns>
+ public static ModelBuilder UseValueConverterForType<T>(this ModelBuilder modelBuilder, ValueConverter converter)
+ {
+ var type = typeof(T);
+ foreach (var entityType in modelBuilder.Model.GetEntityTypes())
+ {
+ foreach (var property in entityType.GetProperties())
+ {
+ if (property.ClrType == type)
+ {
+ property.SetValueConverter(converter);
+ }
+ }
+ }
+
+ return modelBuilder;
+ }
+
+ /// <summary>
+ /// Specify the default <see cref="DateTimeKind"/>.
+ /// </summary>
+ /// <param name="modelBuilder">The model builder to extend.</param>
+ /// <param name="kind">The <see cref="DateTimeKind"/> to specify.</param>
+ public static void SetDefaultDateTimeKind(this ModelBuilder modelBuilder, DateTimeKind kind)
+ {
+ modelBuilder.UseValueConverterForType<DateTime>(new DateTimeKindValueConverter(kind));
+ modelBuilder.UseValueConverterForType<DateTime?>(new DateTimeKindValueConverter(kind));
+ }
+ }
+} \ No newline at end of file
diff --git a/Jellyfin.Server.Implementations/ValueConverters/DateTimeKindValueConverter.cs b/Jellyfin.Server.Implementations/ValueConverters/DateTimeKindValueConverter.cs
new file mode 100644
index 000000000..8a510898b
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ValueConverters/DateTimeKindValueConverter.cs
@@ -0,0 +1,21 @@
+using System;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.ValueConverters
+{
+ /// <summary>
+ /// ValueConverter to specify kind.
+ /// </summary>
+ public class DateTimeKindValueConverter : ValueConverter<DateTime, DateTime>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DateTimeKindValueConverter"/> class.
+ /// </summary>
+ /// <param name="kind">The kind to specify.</param>
+ /// <param name="mappingHints">The mapping hints.</param>
+ public DateTimeKindValueConverter(DateTimeKind kind, ConverterMappingHints mappingHints = null)
+ : base(v => v.ToUniversalTime(), v => DateTime.SpecifyKind(v, kind), mappingHints)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 6cb88c9f7..e5b9620f7 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -285,20 +285,17 @@ namespace Jellyfin.Server.Extensions
private static void AddSwaggerTypeMappings(this SwaggerGenOptions options)
{
/*
- * TODO remove when System.Text.Json supports non-string keys.
- * Used in Jellyfin.Api.Controller.GetChannels.
+ * TODO remove when System.Text.Json properly supports non-string keys.
+ * Used in BaseItemDto.ImageBlurHashes
*/
options.MapType<Dictionary<ImageType, string>>(() =>
new OpenApiSchema
{
Type = "object",
- Properties = typeof(ImageType).GetEnumNames().ToDictionary(
- name => name,
- name => new OpenApiSchema
- {
- Type = "string",
- Format = "string"
- })
+ AdditionalProperties = new OpenApiSchema
+ {
+ Type = "string"
+ }
});
/*
@@ -312,16 +309,10 @@ namespace Jellyfin.Server.Extensions
name => name,
name => new OpenApiSchema
{
- Type = "object", Properties = new Dictionary<string, OpenApiSchema>
+ Type = "object",
+ AdditionalProperties = new OpenApiSchema
{
- {
- "string",
- new OpenApiSchema
- {
- Type = "string",
- Format = "string"
- }
- }
+ Type = "string"
}
})
});
diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs
index 4ffcb940f..f144dd12e 100644
--- a/Jellyfin.Server/Startup.cs
+++ b/Jellyfin.Server/Startup.cs
@@ -81,7 +81,7 @@ namespace Jellyfin.Server
{
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})"));
- c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
+ c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
})
.ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler());
diff --git a/MediaBrowser.Common/Json/Converters/JsonDateTimeIso8601Converter.cs b/MediaBrowser.Common/Json/Converters/JsonDateTimeIso8601Converter.cs
deleted file mode 100644
index 63b344a9d..000000000
--- a/MediaBrowser.Common/Json/Converters/JsonDateTimeIso8601Converter.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Globalization;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace MediaBrowser.Common.Json.Converters
-{
- /// <summary>
- /// Returns an ISO8601 formatted datetime.
- /// </summary>
- /// <remarks>
- /// Used for legacy compatibility.
- /// </remarks>
- public class JsonDateTimeIso8601Converter : JsonConverter<DateTime>
- {
- /// <inheritdoc />
- public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- => reader.GetDateTime();
-
- /// <inheritdoc />
- public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
- => writer.WriteStringValue(value.ToString("O", CultureInfo.InvariantCulture));
- }
-}
diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs
index 1aaf4a43b..c5050a21d 100644
--- a/MediaBrowser.Common/Json/JsonDefaults.cs
+++ b/MediaBrowser.Common/Json/JsonDefaults.cs
@@ -43,7 +43,6 @@ namespace MediaBrowser.Common.Json
options.Converters.Add(new JsonVersionConverter());
options.Converters.Add(new JsonStringEnumConverter());
options.Converters.Add(new JsonNullableStructConverterFactory());
- options.Converters.Add(new JsonDateTimeIso8601Converter());
return options;
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 07f381881..6320b01b8 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -143,26 +143,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The video3 D format.</value>
public Video3DFormat? Video3DFormat { get; set; }
- public string[] GetPlayableStreamFileNames()
- {
- var videoType = VideoType;
-
- if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.BluRay)
- {
- videoType = VideoType.BluRay;
- }
- else if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.Dvd)
- {
- videoType = VideoType.Dvd;
- }
- else
- {
- return Array.Empty<string>();
- }
-
- throw new NotImplementedException();
- }
-
/// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
@@ -415,31 +395,6 @@ namespace MediaBrowser.Controller.Entities
return updateType;
}
- public static string[] QueryPlayableStreamFiles(string rootPath, VideoType videoType)
- {
- if (videoType == VideoType.Dvd)
- {
- return FileSystem.GetFiles(rootPath, new[] { ".vob" }, false, true)
- .OrderByDescending(i => i.Length)
- .ThenBy(i => i.FullName)
- .Take(1)
- .Select(i => i.FullName)
- .ToArray();
- }
-
- if (videoType == VideoType.BluRay)
- {
- return FileSystem.GetFiles(rootPath, new[] { ".m2ts" }, false, true)
- .OrderByDescending(i => i.Length)
- .ThenBy(i => i.FullName)
- .Take(1)
- .Select(i => i.FullName)
- .ToArray();
- }
-
- return Array.Empty<string>();
- }
-
/// <summary>
/// Gets a value indicating whether [is3 D].
/// </summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 9c6bbb916..91a03e647 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -390,25 +390,9 @@ namespace MediaBrowser.Controller.MediaEncoding
public string GetInputPathArgument(EncodingJobInfo state)
{
- var protocol = state.InputProtocol;
var mediaPath = state.MediaPath ?? string.Empty;
- string[] inputPath;
- if (state.IsInputVideo
- && !(state.VideoType == VideoType.Iso && state.IsoMount == null))
- {
- inputPath = MediaEncoderHelpers.GetInputArgument(
- _fileSystem,
- mediaPath,
- state.IsoMount,
- state.PlayableStreamFileNames);
- }
- else
- {
- inputPath = new[] { mediaPath };
- }
-
- return _mediaEncoder.GetInputArgument(inputPath, protocol);
+ return _mediaEncoder.GetInputArgument(mediaPath, state.MediaSource);
}
/// <summary>
@@ -2673,18 +2657,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- public string GetProbeSizeArgument(int numInputFiles)
- => numInputFiles > 1 ? "-probesize " + _configuration.GetFFmpegProbeSize() : string.Empty;
-
- public string GetAnalyzeDurationArgument(int numInputFiles)
- => numInputFiles > 1 ? "-analyzeduration " + _configuration.GetFFmpegAnalyzeDuration() : string.Empty;
-
public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions)
{
var inputModifier = string.Empty;
-
- var numInputFiles = state.PlayableStreamFileNames.Length > 0 ? state.PlayableStreamFileNames.Length : 1;
- var probeSizeArgument = GetProbeSizeArgument(numInputFiles);
+ var probeSizeArgument = string.Empty;
string analyzeDurationArgument;
if (state.MediaSource.AnalyzeDurationMs.HasValue)
@@ -2693,7 +2669,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else
{
- analyzeDurationArgument = GetAnalyzeDurationArgument(numInputFiles);
+ analyzeDurationArgument = string.Empty;
}
if (!string.IsNullOrEmpty(probeSizeArgument))
@@ -2877,32 +2853,6 @@ namespace MediaBrowser.Controller.MediaEncoding
state.IsoType = mediaSource.IsoType;
- if (mediaSource.VideoType.HasValue)
- {
- state.VideoType = mediaSource.VideoType.Value;
-
- if (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd)
- {
- state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, mediaSource.VideoType.Value).Select(Path.GetFileName).ToArray();
- }
- else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.BluRay)
- {
- state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.BluRay).Select(Path.GetFileName).ToArray();
- }
- else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.Dvd)
- {
- state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.Dvd).Select(Path.GetFileName).ToArray();
- }
- else
- {
- state.PlayableStreamFileNames = Array.Empty<string>();
- }
- }
- else
- {
- state.PlayableStreamFileNames = Array.Empty<string>();
- }
-
if (mediaSource.Timestamp.HasValue)
{
state.InputTimestamp = mediaSource.Timestamp.Value;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 52794a69b..dacd6dea6 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -33,10 +33,6 @@ namespace MediaBrowser.Controller.MediaEncoding
public bool IsInputVideo { get; set; }
- public IIsoMount IsoMount { get; set; }
-
- public string[] PlayableStreamFileNames { get; set; }
-
public string OutputAudioCodec { get; set; }
public int? OutputVideoBitrate { get; set; }
@@ -313,7 +309,6 @@ namespace MediaBrowser.Controller.MediaEncoding
{
TranscodingType = jobType;
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- PlayableStreamFileNames = Array.Empty<string>();
SupportedAudioCodecs = Array.Empty<string>();
SupportedVideoCodecs = Array.Empty<string>();
SupportedSubtitleCodecs = Array.Empty<string>();
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index f6bc1f4de..e7f042d2f 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
@@ -61,18 +62,18 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Extracts the video image.
/// </summary>
- Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
+ Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
- Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
+ Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
/// <summary>
/// Extracts the video images on interval.
/// </summary>
Task ExtractVideoImagesOnInterval(
- string[] inputFiles,
+ string inputFile,
string container,
MediaStream videoStream,
- MediaProtocol protocol,
+ MediaSourceInfo mediaSource,
Video3DFormat? threedFormat,
TimeSpan interval,
string targetDirectory,
@@ -91,10 +92,10 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the input argument.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
+ /// <param name="inputFile">The input file.</param>
+ /// <param name="mediaSource">The mediaSource.</param>
/// <returns>System.String.</returns>
- string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol);
+ string GetInputArgument(string inputFile, MediaSourceInfo mediaSource);
/// <summary>
/// Gets the time parameter.
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index ce53c23ad..281d50372 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -13,38 +13,5 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
public static class MediaEncoderHelpers
{
- /// <summary>
- /// Gets the input argument.
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="videoPath">The video path.</param>
- /// <param name="isoMount">The iso mount.</param>
- /// <param name="playableStreamFileNames">The playable stream file names.</param>
- /// <returns>string[].</returns>
- public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, IIsoMount isoMount, IReadOnlyCollection<string> playableStreamFileNames)
- {
- if (playableStreamFileNames.Count > 0)
- {
- if (isoMount == null)
- {
- return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames);
- }
-
- return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames);
- }
-
- return new[] { videoPath };
- }
-
- private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, IEnumerable<string> filenames)
- {
- var allFiles = fileSystem
- .GetFilePaths(rootPath, true)
- .ToArray();
-
- return filenames.Select(name => allFiles.FirstOrDefault(f => string.Equals(Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
- .Where(f => !string.IsNullOrEmpty(f))
- .ToArray();
- }
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
index 59729de49..2cb04bdc4 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
@@ -1,9 +1,7 @@
#pragma warning disable CS1591
-using System;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -14,14 +12,5 @@ namespace MediaBrowser.Controller.MediaEncoding
public bool ExtractChapters { get; set; }
public DlnaProfileType MediaType { get; set; }
-
- public IIsoMount MountedIso { get; set; }
-
- public string[] PlayableStreamFileNames { get; set; }
-
- public MediaInfoRequest()
- {
- PlayableStreamFileNames = Array.Empty<string>();
- }
}
}
diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs
index 0194c596f..93573e08e 100644
--- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs
+++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs
@@ -58,5 +58,10 @@ namespace MediaBrowser.Controller.Net
/// Gets or sets a value indicating whether the token is authenticated.
/// </summary>
public bool IsAuthenticated { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the request has a token.
+ /// </summary>
+ public bool HasToken { get; set; }
}
}
diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
index bc940d0b8..e8aeabf9d 100644
--- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
+++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs
@@ -87,19 +87,19 @@ namespace MediaBrowser.MediaEncoding.Attachments
MediaAttachment mediaAttachment,
CancellationToken cancellationToken)
{
- var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false);
+ var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource, mediaAttachment, cancellationToken).ConfigureAwait(false);
return File.OpenRead(attachmentPath);
}
private async Task<string> GetReadableFile(
string mediaPath,
string inputFile,
- MediaProtocol protocol,
+ MediaSourceInfo mediaSource,
MediaAttachment mediaAttachment,
CancellationToken cancellationToken)
{
- var outputPath = GetAttachmentCachePath(mediaPath, protocol, mediaAttachment.Index);
- await ExtractAttachment(inputFile, protocol, mediaAttachment.Index, outputPath, cancellationToken)
+ var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, mediaAttachment.Index);
+ await ExtractAttachment(inputFile, mediaSource, mediaAttachment.Index, outputPath, cancellationToken)
.ConfigureAwait(false);
return outputPath;
@@ -107,7 +107,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
private async Task ExtractAttachment(
string inputFile,
- MediaProtocol protocol,
+ MediaSourceInfo mediaSource,
int attachmentStreamIndex,
string outputPath,
CancellationToken cancellationToken)
@@ -121,7 +121,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
if (!File.Exists(outputPath))
{
await ExtractAttachmentInternal(
- _mediaEncoder.GetInputArgument(new[] { inputFile }, protocol),
+ _mediaEncoder.GetInputArgument(inputFile, mediaSource),
attachmentStreamIndex,
outputPath,
cancellationToken).ConfigureAwait(false);
@@ -234,10 +234,10 @@ namespace MediaBrowser.MediaEncoding.Attachments
}
}
- private string GetAttachmentCachePath(string mediaPath, MediaProtocol protocol, int attachmentStreamIndex)
+ private string GetAttachmentCachePath(string mediaPath, MediaSourceInfo mediaSource, int attachmentStreamIndex)
{
string filename;
- if (protocol == MediaProtocol.File)
+ if (mediaSource.Protocol == MediaProtocol.File)
{
var date = _fileSystem.GetLastWriteTimeUtc(mediaPath);
filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture);
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
index 63310fdf6..d0ea0429b 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
@@ -1,53 +1,44 @@
#pragma warning disable CS1591
using System;
-using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.MediaEncoding.Encoder
{
public static class EncodingUtils
{
- public static string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol)
+ public static string GetInputArgument(string inputPrefix, string inputFile, MediaProtocol protocol)
{
if (protocol != MediaProtocol.File)
{
- var url = inputFiles[0];
-
- return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", url);
+ return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", inputFile);
}
- return GetConcatInputArgument(inputFiles);
+ return GetConcatInputArgument(inputFile, inputPrefix);
}
/// <summary>
/// Gets the concat input argument.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
+ /// <param name="inputFile">The input file.</param>
+ /// <param name="inputPrefix">The input prefix.</param>
/// <returns>System.String.</returns>
- private static string GetConcatInputArgument(IReadOnlyList<string> inputFiles)
+ private static string GetConcatInputArgument(string inputFile, string inputPrefix)
{
// Get all streams
// If there's more than one we'll need to use the concat command
- if (inputFiles.Count > 1)
- {
- var files = string.Join("|", inputFiles.Select(NormalizePath));
-
- return string.Format(CultureInfo.InvariantCulture, "concat:\"{0}\"", files);
- }
-
// Determine the input path for video files
- return GetFileInputArgument(inputFiles[0]);
+ return GetFileInputArgument(inputFile, inputPrefix);
}
/// <summary>
/// Gets the file input argument.
/// </summary>
/// <param name="path">The path.</param>
+ /// <param name="inputPrefix">The path prefix.</param>
/// <returns>System.String.</returns>
- private static string GetFileInputArgument(string path)
+ private static string GetFileInputArgument(string path, string inputPrefix)
{
if (path.IndexOf("://", StringComparison.Ordinal) != -1)
{
@@ -57,7 +48,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Quotes are valid path characters in linux and they need to be escaped here with a leading \
path = NormalizePath(path);
- return string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", path);
+ return string.Format(CultureInfo.InvariantCulture, "{1}:\"{0}\"", path, inputPrefix);
}
/// <summary>
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index bfc09cc97..380894278 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -18,6 +18,7 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
@@ -88,8 +89,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
_jsonSerializerOptions = JsonDefaults.GetOptions();
}
- private EncodingHelper EncodingHelper => _encodingHelperFactory.Value;
-
/// <inheritdoc />
public string EncoderPath => _ffmpegPath;
@@ -325,33 +324,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
{
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
+ var inputFile = request.MediaSource.Path;
- var inputFiles = MediaEncoderHelpers.GetInputArgument(_fileSystem, request.MediaSource.Path, request.MountedIso, request.PlayableStreamFileNames);
-
- var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
- string analyzeDuration;
+ string analyzeDuration = string.Empty;
if (request.MediaSource.AnalyzeDurationMs > 0)
{
analyzeDuration = "-analyzeduration " +
(request.MediaSource.AnalyzeDurationMs * 1000).ToString();
}
- else
- {
- analyzeDuration = EncodingHelper.GetAnalyzeDurationArgument(inputFiles.Length);
- }
-
- probeSize = probeSize + " " + analyzeDuration;
- probeSize = probeSize.Trim();
var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File;
return GetMediaInfoInternal(
- GetInputArgument(inputFiles, request.MediaSource.Protocol),
+ GetInputArgument(inputFile, request.MediaSource),
request.MediaSource.Path,
request.MediaSource.Protocol,
extractChapters,
- probeSize,
+ analyzeDuration,
request.MediaType == DlnaProfileType.Audio,
request.MediaSource.VideoType,
forceEnableLogging,
@@ -361,12 +351,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <summary>
/// Gets the input argument.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
+ /// <param name="inputFile">The input file.</param>
+ /// <param name="mediaSource">The mediaSource.</param>
/// <returns>System.String.</returns>
/// <exception cref="ArgumentException">Unrecognized InputType.</exception>
- public string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol)
- => EncodingUtils.GetInputArgument(inputFiles, protocol);
+ public string GetInputArgument(string inputFile, MediaSourceInfo mediaSource)
+ {
+ var prefix = "file";
+ if (mediaSource.VideoType == VideoType.BluRay || mediaSource.VideoType == VideoType.Iso)
+ {
+ prefix = "bluray";
+ }
+
+ return EncodingUtils.GetInputArgument(prefix, inputFile, mediaSource.Protocol);
+ }
/// <summary>
/// Gets the media info internal.
@@ -464,31 +462,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken)
{
- return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken);
+ var mediaSource = new MediaSourceInfo
+ {
+ Protocol = MediaProtocol.File
+ };
+
+ return ExtractImage(path, null, null, imageStreamIndex, mediaSource, true, null, null, cancellationToken);
}
- public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
+ public Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
{
- return ExtractImage(inputFiles, container, videoStream, null, protocol, false, threedFormat, offset, cancellationToken);
+ return ExtractImage(inputFile, container, videoStream, null, mediaSource, false, threedFormat, offset, cancellationToken);
}
- public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken)
+ public Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken)
{
- return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken);
+ return ExtractImage(inputFile, container, imageStream, imageStreamIndex, mediaSource, false, null, null, cancellationToken);
}
private async Task<string> ExtractImage(
- string[] inputFiles,
+ string inputFile,
string container,
MediaStream videoStream,
int? imageStreamIndex,
- MediaProtocol protocol,
+ MediaSourceInfo mediaSource,
bool isAudio,
Video3DFormat? threedFormat,
TimeSpan? offset,
CancellationToken cancellationToken)
{
- var inputArgument = GetInputArgument(inputFiles, protocol);
+ var inputArgument = GetInputArgument(inputFile, mediaSource);
if (isAudio)
{
@@ -615,8 +618,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 {2} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, threads);
- var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
- var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
+ var probeSizeArgument = string.Empty;
+ var analyzeDurationArgument = string.Empty;
if (!string.IsNullOrWhiteSpace(probeSizeArgument))
{
@@ -725,10 +728,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
public async Task ExtractVideoImagesOnInterval(
- string[] inputFiles,
+ string inputFile,
string container,
MediaStream videoStream,
- MediaProtocol protocol,
+ MediaSourceInfo mediaSource,
Video3DFormat? threedFormat,
TimeSpan interval,
string targetDirectory,
@@ -736,7 +739,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
int? maxWidth,
CancellationToken cancellationToken)
{
- var inputArgument = GetInputArgument(inputFiles, protocol);
+ var inputArgument = GetInputArgument(inputFile, mediaSource);
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture);
@@ -752,8 +755,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads {3} -v quiet {2} -f image2 \"{1}\"", inputArgument, outputPath, vf, threads);
- var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
- var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
+ var probeSizeArgument = string.Empty;
+ var analyzeDurationArgument = string.Empty;
if (!string.IsNullOrWhiteSpace(probeSizeArgument))
{
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 27bd693e3..bd026bce1 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -782,7 +782,7 @@ namespace MediaBrowser.MediaEncoding.Probing
if (bitrate == 0
&& formatInfo != null
&& !string.IsNullOrEmpty(formatInfo.BitRate)
- && (stream.Type == MediaStreamType.Video || stream.Type == MediaStreamType.Audio))
+ && (stream.Type == MediaStreamType.Video || (isAudio && stream.Type == MediaStreamType.Audio)))
{
// If the stream info doesn't have a bitrate get the value from the media format info
if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, _usCulture, out var value))
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index b61b8a0e0..b92c4ee06 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -168,18 +168,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
MediaStream subtitleStream,
CancellationToken cancellationToken)
{
- string[] inputFiles;
-
- if (mediaSource.VideoType.HasValue
- && (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd))
- {
- var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id));
- inputFiles = mediaSourceItem.GetPlayableStreamFileNames();
- }
- else
- {
- inputFiles = new[] { mediaSource.Path };
- }
+ var inputFile = mediaSource.Path;
var protocol = mediaSource.Protocol;
if (subtitleStream.IsExternal)
@@ -187,7 +176,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path);
}
- var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
+ var fileInfo = await GetReadableFile(mediaSource.Path, inputFile, mediaSource, subtitleStream, cancellationToken).ConfigureAwait(false);
var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false);
@@ -220,8 +209,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private async Task<SubtitleInfo> GetReadableFile(
string mediaPath,
- string[] inputFiles,
- MediaProtocol protocol,
+ string inputFile,
+ MediaSourceInfo mediaSource,
MediaStream subtitleStream,
CancellationToken cancellationToken)
{
@@ -252,9 +241,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
// Extract
- var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, "." + outputFormat);
+ var outputPath = GetSubtitleCachePath(mediaPath, mediaSource, subtitleStream.Index, "." + outputFormat);
- await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
+ await ExtractTextSubtitle(inputFile, mediaSource, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
.ConfigureAwait(false);
return new SubtitleInfo(outputPath, MediaProtocol.File, outputFormat, false);
@@ -266,14 +255,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (GetReader(currentFormat, false) == null)
{
// Convert
- var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt");
+ var outputPath = GetSubtitleCachePath(mediaPath, mediaSource, subtitleStream.Index, ".srt");
- await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, protocol, outputPath, cancellationToken).ConfigureAwait(false);
+ await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true);
}
- return new SubtitleInfo(subtitleStream.Path, protocol, currentFormat, true);
+ return new SubtitleInfo(subtitleStream.Path, mediaSource.Protocol, currentFormat, true);
}
private ISubtitleParser GetReader(string format, bool throwIfMissing)
@@ -363,11 +352,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param>
- /// <param name="inputProtocol">The input protocol.</param>
+ /// <param name="mediaSource">The input mediaSource.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
+ private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{
var semaphore = GetLock(outputPath);
@@ -377,7 +366,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
if (!File.Exists(outputPath))
{
- await ConvertTextSubtitleToSrtInternal(inputPath, language, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false);
+ await ConvertTextSubtitleToSrtInternal(inputPath, language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -391,14 +380,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param>
- /// <param name="inputProtocol">The input protocol.</param>
+ /// <param name="mediaSource">The input mediaSource.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="ArgumentNullException">
/// The <c>inputPath</c> or <c>outputPath</c> is <c>null</c>.
/// </exception>
- private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
+ private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(inputPath))
{
@@ -412,7 +401,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
- var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);
+ var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, mediaSource.Protocol, cancellationToken).ConfigureAwait(false);
// FFmpeg automatically convert character encoding when it is UTF-16
// If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event"
@@ -515,8 +504,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <summary>
/// Extracts the text subtitle.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
+ /// <param name="inputFile">The input file.</param>
+ /// <param name="mediaSource">The mediaSource.</param>
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
/// <param name="outputCodec">The output codec.</param>
/// <param name="outputPath">The output path.</param>
@@ -524,8 +513,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <returns>Task.</returns>
/// <exception cref="ArgumentException">Must use inputPath list overload.</exception>
private async Task ExtractTextSubtitle(
- string[] inputFiles,
- MediaProtocol protocol,
+ string inputFile,
+ MediaSourceInfo mediaSource,
int subtitleStreamIndex,
string outputCodec,
string outputPath,
@@ -540,7 +529,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (!File.Exists(outputPath))
{
await ExtractTextSubtitleInternal(
- _mediaEncoder.GetInputArgument(inputFiles, protocol),
+ _mediaEncoder.GetInputArgument(inputFile, mediaSource),
subtitleStreamIndex,
outputCodec,
outputPath,
@@ -706,9 +695,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- private string GetSubtitleCachePath(string mediaPath, MediaProtocol protocol, int subtitleStreamIndex, string outputSubtitleExtension)
+ private string GetSubtitleCachePath(string mediaPath, MediaSourceInfo mediaSource, int subtitleStreamIndex, string outputSubtitleExtension)
{
- if (protocol == MediaProtocol.File)
+ if (mediaSource.Protocol == MediaProtocol.File)
{
var ticksParam = string.Empty;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index c61187fdf..648329757 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -150,11 +150,6 @@ namespace MediaBrowser.Providers.MediaInfo
public Task<ItemUpdateType> FetchVideoInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
where T : Video
{
- if (item.VideoType == VideoType.Iso)
- {
- return _cachedTask;
- }
-
if (item.IsPlaceHolder)
{
return _cachedTask;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 776dee780..6d39c091e 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -116,7 +116,7 @@ namespace MediaBrowser.Providers.MediaInfo
streamFileNames = Array.Empty<string>();
}
- mediaInfoResult = await GetMediaInfo(item, streamFileNames, cancellationToken).ConfigureAwait(false);
+ mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
}
@@ -128,7 +128,6 @@ namespace MediaBrowser.Providers.MediaInfo
private Task<Model.MediaInfo.MediaInfo> GetMediaInfo(
Video item,
- string[] streamFileNames,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -145,7 +144,6 @@ namespace MediaBrowser.Providers.MediaInfo
return _mediaEncoder.GetMediaInfo(
new MediaInfoRequest
{
- PlayableStreamFileNames = streamFileNames,
ExtractChapters = true,
MediaType = DlnaProfileType.Video,
MediaSource = new MediaSourceInfo
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index fc38d3832..c36c3af6a 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
@@ -50,7 +51,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
// No support for this
- if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.BluRay)
+ if (video.VideoType == VideoType.Dvd)
{
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
@@ -69,11 +70,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var protocol = item.PathProtocol ?? MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(
- _fileSystem,
- item.Path,
- null,
- item.GetPlayableStreamFileNames());
+ var inputPath = item.Path;
var mediaStreams =
item.GetMediaStreams();
@@ -107,7 +104,14 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, imageStream, videoIndex, cancellationToken).ConfigureAwait(false);
+ MediaSourceInfo mediaSource = new MediaSourceInfo
+ {
+ VideoType = item.VideoType,
+ IsoType = item.IsoType,
+ Protocol = item.PathProtocol.Value,
+ };
+
+ extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, imageStream, videoIndex, cancellationToken).ConfigureAwait(false);
}
else
{
@@ -119,8 +123,14 @@ namespace MediaBrowser.Providers.MediaInfo
: TimeSpan.FromSeconds(10);
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+ var mediaSource = new MediaSourceInfo
+ {
+ VideoType = item.VideoType,
+ IsoType = item.IsoType,
+ Protocol = item.PathProtocol.Value,
+ };
- extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
+ extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
}
return new DynamicImageResponse
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index cb204137b..5a807372d 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -1,4 +1,4 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30503.244
MinimumVisualStudioVersion = 10.0.40219.1
@@ -70,6 +70,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Networking", "Jell
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Networking.Tests", "tests\Jellyfin.Networking.Tests\NetworkTesting\Jellyfin.Networking.Tests.csproj", "{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Dlna.Tests", "tests\Jellyfin.Dlna.Tests\Jellyfin.Dlna.Tests.csproj", "{B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -188,6 +190,10 @@ Global
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -200,6 +206,7 @@ Global
{2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{462584F7-5023-4019-9EAC-B98CA458C0A0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
index 90c491666..ee20cc573 100644
--- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
@@ -69,7 +69,7 @@ namespace Jellyfin.Api.Tests.Auth
}
[Fact]
- public async Task HandleAuthenticateAsyncShouldFailOnAuthenticationException()
+ public async Task HandleAuthenticateAsyncShouldProvideNoResultOnAuthenticationException()
{
var errorMessage = _fixture.Create<string>();
@@ -81,7 +81,7 @@ namespace Jellyfin.Api.Tests.Auth
var authenticateResult = await _sut.AuthenticateAsync();
Assert.False(authenticateResult.Succeeded);
- Assert.Equal(errorMessage, authenticateResult.Failure?.Message);
+ Assert.True(authenticateResult.None);
}
[Fact]
diff --git a/tests/Jellyfin.Dlna.Tests/GetUuidTests.cs b/tests/Jellyfin.Dlna.Tests/GetUuidTests.cs
new file mode 100644
index 000000000..7655e3f7c
--- /dev/null
+++ b/tests/Jellyfin.Dlna.Tests/GetUuidTests.cs
@@ -0,0 +1,17 @@
+using Emby.Dlna.PlayTo;
+using Xunit;
+
+namespace Jellyfin.Dlna.Tests
+{
+ public static class GetUuidTests
+ {
+ [Theory]
+ [InlineData("uuid:fc4ec57e-b051-11db-88f8-0060085db3f6::urn:schemas-upnp-org:device:WANDevice:1", "fc4ec57e-b051-11db-88f8-0060085db3f6")]
+ [InlineData("uuid:IGD{8c80f73f-4ba0-45fa-835d-042505d052be}000000000000", "8c80f73f-4ba0-45fa-835d-042505d052be")]
+ [InlineData("uuid:IGD{8c80f73f-4ba0-45fa-835d-042505d052be}000000000000::urn:schemas-upnp-org:device:InternetGatewayDevice:1", "8c80f73f-4ba0-45fa-835d-042505d052be")]
+ [InlineData("uuid:00000000-0000-0000-0000-000000000000::upnp:rootdevice", "00000000-0000-0000-0000-000000000000")]
+ [InlineData("uuid:fc4ec57e-b051-11db-88f8-0060085db3f6", "fc4ec57e-b051-11db-88f8-0060085db3f6")]
+ public static void GetUuid_Valid_Success(string usn, string uuid)
+ => Assert.Equal(uuid, PlayToManager.GetUuid(usn));
+ }
+}
diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
new file mode 100644
index 000000000..f91db6744
--- /dev/null
+++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
+ <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
+ <PackageReference Include="coverlet.collector" Version="1.3.0" />
+ </ItemGroup>
+
+ <!-- Code Analyzers -->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../../Emby.Dlna/Emby.Dlna.csproj" />
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+</Project>