Compare commits

..

93 Commits

Author SHA1 Message Date
Joshua M. Boniface
383d514353 Bump version to 10.8.8 2022-11-29 13:42:58 -05:00
Bond-009
6fc8237242 Merge pull request #8753 from thornbill/fix-items-access-backport 2022-11-22 21:52:53 +01:00
Bill Thornton
79d7a4d4df Remove unused using statement 2022-11-16 10:27:41 -05:00
Bill Thornton
e90031b4cc Use elevated access control for media folders endpoint 2022-11-15 16:52:49 -05:00
Bill Thornton
4f3d562d75 Fix media folders endpoint access control 2022-11-15 16:49:03 -05:00
Bill Thornton
6c8b40f413 Fix items endpoint not honoring library access control 2022-11-15 16:35:05 -05:00
Joshua M. Boniface
ec81dc9be2 Bump version to 10.8.7 2022-10-31 23:07:09 -04:00
Joshua M. Boniface
45f3fb1cfc Merge pull request #8662 from cvium/this_next_up_fix_wont_work_either 2022-10-31 17:05:38 -04:00
Cody Robibero
f83a24ec43 Merge pull request #8667 from daullmer/backport-omdb-fix 2022-10-31 14:33:33 -06:00
Joshua M. Boniface
84c03a2d93 Merge pull request #8649 from jellyfin/revert-8480-revert-data-streams 2022-10-31 12:55:56 -04:00
David Ullmer
bc8e249080 Enable OMDB plot for non-English languages as fallback 2022-10-31 13:10:00 +01:00
cvium
5ea9a74289 fix: use a combination of ParentIndexNumber and IndexNumber to determine next up episodes 2022-10-30 16:06:47 +01:00
Niels van Velzen
987d31ea16 Revert "Revert "Merge pull request #8298 from lomion0815/fix-data-stream"" 2022-10-29 11:38:14 +02:00
Joshua M. Boniface
f850779781 Bump version to 10.8.6 2022-10-28 22:41:11 -04:00
Claus Vium
3bdc2bff5f Merge pull request #8620 from nyanmisaka/fix-dg2-tonemap-tearing
Fix the DG2 HDR TM tearing issue on Windows
2022-10-25 12:43:47 +02:00
nyanmisaka
5c6a84549a Fix some encoding presets
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2022-10-25 16:26:55 +08:00
nyanmisaka
48da35f91f Fix the DG2 HDR TM tearing issue on Windows
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2022-10-25 16:26:55 +08:00
Claus Vium
39b29eb9f1 Merge pull request #8608 from cvium/activitylog_datecreated_index
Add index for DateCreated on ActivityLogs
2022-10-24 18:46:54 +02:00
Anthony Lavado
a6740bf51e Merge pull request #8609 from anthonylavado/sd-image-fix 2022-10-23 13:37:29 -04:00
cvium
c7797d3ead fix build 2022-10-23 18:54:43 +02:00
Claus Vium
c86d5838be Merge pull request #8611 from nielsvanvelzen/transcodereasons 2022-10-22 14:17:47 +02:00
Niels van Velzen
43223b9036 Fix TranscodeReasons type in OpenAPI output 2022-10-22 13:59:24 +02:00
Anthony Lavado
c71385d2db Add token for program metadata download 2022-10-22 04:30:45 -04:00
Anthony Lavado
ad5becc524 Use token when retrieving images 2022-10-22 04:10:20 -04:00
cvium
7c75dcfb9c use filescoped namespace 2022-10-22 10:04:50 +02:00
cvium
7937e31a9b add index for DateCreated on ActivityLog 2022-10-22 10:02:52 +02:00
Claus Vium
1f1f26306b Merge pull request #8600 from Shadowghost/10.8-slow-load 2022-10-21 17:44:38 +02:00
Shadowghost
577399ca05 Prevent host lookup on GetSmartUrl for HTTP requests 2022-10-21 10:09:45 +02:00
Bond-009
e7ea7c0383 Merge pull request #8523 from Gylesie/tweak-lastplayeddate 2022-10-10 19:29:03 +02:00
Gylesie
9fe7751d05 Fallback only to the current time when marking item as watched 2022-10-09 11:28:49 +02:00
Claus Vium
bf129ab9b8 Merge pull request #8411 from Maxr1998/audio-stream-fix
Allow direct play even if no audio stream is available
2022-10-09 09:08:01 +02:00
Claus Vium
6d23de64c0 Merge pull request #8516 from cvium/kill_ffprobe_when_extraction_crashes 2022-10-09 08:27:34 +02:00
Claus Vium
e4f48bb486 Merge pull request #8517 from cvium/backport_8335 2022-10-09 08:27:22 +02:00
Andreas Egli
866b4460b1 change variable to camelCase 2022-10-08 19:00:36 +02:00
Andreas Egli
9db0b275ff allow additional flags after K_ for ffprobe keyframe extraction 2022-10-08 19:00:23 +02:00
Andreas Egli
14008fd7d0 add gentps flag to ffprobe for keyframe extraction 2022-10-08 19:00:02 +02:00
Andreas Egli
8532d88a71 add TryParse to FFProbe Keyframe extraction 2022-10-08 18:59:43 +02:00
cvium
737c739d33 fix: kill ffprobe if keyframe parsing fails 2022-10-08 18:56:07 +02:00
Claus Vium
679e83082f Merge pull request #8501 from cvium/fix_nextup 2022-10-07 07:50:04 +02:00
Claus Vium
d8e53f35a5 Merge pull request #8499 from cvium/add_basque_language 2022-10-07 07:49:17 +02:00
cvium
7a0e7b3cf8 add MinParentIndexNumber 2022-10-06 14:21:21 +02:00
cvium
373c63bcc7 fix: set MinIndexNumber for the next up query 2022-10-06 14:06:24 +02:00
cvium
be5d343efb chore: add Basque to the list of localization options 2022-10-06 09:44:11 +02:00
Cody Robibero
c9c91cc34e Merge pull request #8480 from thornbill/revert-data-streams 2022-10-01 08:52:39 -06:00
Bill Thornton
774b4a0d3f Revert "Merge pull request #8298 from lomion0815/fix-data-stream"
This reverts commit 848ea703bc, reversing
changes made to af87706379.
2022-10-01 00:56:46 -04:00
Joshua M. Boniface
a26cded0f5 Bump version to 10.8.5 2022-09-24 22:01:59 -04:00
Joshua M. Boniface
4ec82ec662 Merge pull request #8433 from jellyfin/dotnet-6.0.9 2022-09-20 09:45:01 -04:00
Cody Robibero
879787212e Update to dotnet 6.0.9 2022-09-19 08:19:32 -06:00
Maxr1998
23100c9b86 Use ICollection for candidateAudioStreams 2022-09-18 22:56:38 +02:00
Bond-009
e6124bc154 Merge pull request #8399 from cvium/respectTagRestrictions 2022-09-15 14:08:50 +02:00
Maxr1998
8753b7200f Allow direct play even if no audio stream is available 2022-09-15 02:04:12 +02:00
Bond-009
88d5230bab Merge pull request #8348 from jellyfin/revert-7985-revert-7961-next_up_idk 2022-09-14 01:54:45 +02:00
LogicalPhallacy
2920c52d61 Reorder and check for query user null to avoid null ref issues 2022-09-13 09:12:38 +02:00
LogicalPhallacy
de196a7687 Forces respecting IsVisible on people 2022-09-13 09:12:38 +02:00
Claus Vium
ba026716c1 Merge pull request #8213 from nyanmisaka/pause-cpu
Fix high single thread usage in throttler
2022-09-13 08:07:04 +02:00
Joshua M. Boniface
125ee88311 Merge pull request #8321 from strugee/fix-systemd-whitespace 2022-09-11 16:55:21 -04:00
nyanmisaka
c53f6a2890 Fix high single thread usage in throttler
this requires jellyfin-ffmpeg >= 5.0.1-8
2022-09-09 21:14:02 +08:00
Bond-009
649b4c49e0 Merge pull request #8327 from RealGreenDragon/subtitle-extraction-timeout-10.8.z 2022-09-09 12:51:25 +02:00
Cody Robibero
848ea703bc Merge pull request #8298 from lomion0815/fix-data-stream 2022-09-05 08:51:48 -06:00
AJ Jordan
0adadff3e7 Fix systemd not breaking whitespace in env vars
This is particularly important for JELLYFIN_ADDITIONAL_OPTS, where the
user is most likely to want to specify more than one word.
2022-08-27 16:20:06 -04:00
MagicGreenDragon
ffdc3a6734 Increased subtitle extraction timeout to 30 min 2022-08-27 18:10:42 +02:00
lomion0815
a51cd4f8db Improved error log as suggested by crobibero in the PR #8298 review 2022-08-24 21:01:32 +02:00
Bond-009
af87706379 Merge pull request #8214 from nielsvanvelzen/optional-userid 2022-08-22 18:25:20 +02:00
Niels van Velzen
8422ab687b Update Jellyfin.Api/Controllers/UniversalAudioController.cs
Co-authored-by: Bond-009 <bond.009@outlook.com>
2022-08-22 17:47:59 +02:00
markus
64753cfc7f Streams with CodecType "data" (like "epg" streams in DVB recordings) get ignored. This results in wrong stream specifiers for all subsequential streams. This fix correctly handles "data" streams without any further processing. 2022-08-22 14:58:30 +02:00
Claus Vium
632fb05f46 Merge pull request #8280 from thornbill/fix-analyze-duration-priority
Fix ffmpeg analyze duration env var taking priority over media source
2022-08-18 08:08:58 +02:00
Claus Vium
527ed0607d Merge pull request #8189 from lukefor/getitems-outofrange
Fix GetItems IndexOutOfRangeException when IDs do not exist
2022-08-18 08:07:51 +02:00
Luke F
b59daab273 Tab -> space 2022-08-18 00:26:55 +01:00
Luke F
8f28d52929 Code review - simplify SortItemsByRequest to a single roughly-equivalent linq expression 2022-08-18 00:15:57 +01:00
Luke F
749b263c48 Merge remote-tracking branch 'upstream/release-10.8.z' into getitems-outofrange 2022-08-18 00:14:01 +01:00
Bill Thornton
80c68b8948 Fix ffmpeg analyze duration env var taking priority over media source 2022-08-17 15:04:51 -04:00
Claus Vium
a5687793c9 Revert "Revert "refactor: use season number and episode number for NextUp ordering instead of SortName"" 2022-08-15 14:10:42 +02:00
Joshua Boniface
b344771f8a Bump version to 10.8.4 2022-08-13 21:51:50 -04:00
Joshua Boniface
3ff78b687d Revert "Restore "Merge pull request #8087 from cvium/generic_subtitleparser""
This reverts commit 5bcab0f0f8.
2022-08-13 21:51:23 -04:00
Joshua M. Boniface
d260f30810 Merge pull request #8257 from joshuaboniface/fix-dotnetargs 2022-08-13 21:45:57 -04:00
Cody Robibero
7ffdde9a0b Merge pull request #8212 from SenorSmartyPants/Add384ResolutionText
Add resolution text for 384 sized video
2022-08-13 18:34:17 -07:00
Joshua M. Boniface
e14194bfe2 Fix remaining instances in root package configs 2022-08-13 21:23:01 -04:00
Joshua M. Boniface
3bf1a7e445 Use separate args for dotnet publish commands
Fixes #8245
2022-08-13 21:18:28 -04:00
Bond-009
1faee43b11 Merge pull request #8182 from Shadowghost/fix-sub-characterset 2022-08-12 19:47:42 +02:00
Joshua M. Boniface
31f9938e3a Merge pull request #8234 from crobibero/dotnet-6.0.8 2022-08-11 22:46:31 -04:00
Cody Robibero
ae9fd4ab35 update remaining dependencies 2022-08-09 17:57:51 -06:00
Cody Robibero
71ed7f7676 update to dotnet 6.0.8 2022-08-09 17:57:21 -06:00
SenorSmartyPants
3b6e003029 Add 404p Resolution Text 2022-08-09 12:09:29 -05:00
Claus Vium
9357d610b1 Merge pull request #8209 from Shadowghost/fix-playback
Fix series query including missing episodes when it should not
2022-08-08 22:57:56 +02:00
Joshua M. Boniface
1d4755894e Merge pull request #8219 from nyanmisaka/fedora-hardening
Move Fedora service hardening options to override config
2022-08-07 21:10:03 -04:00
nyanmisaka
2320f06666 Move Fedora service hardening options to override config 2022-08-07 18:01:26 +08:00
Niels van Velzen
8296f07a39 Make userId truly optional in UniversalAudioController 2022-08-06 14:17:04 +02:00
SenorSmartyPants
30f6263806 Add resolution text for 384 sized video 2022-08-05 23:32:22 -05:00
Shadowghost
a9249393e1 Fix series query including missing episodes when it should not 2022-08-05 19:38:33 +02:00
Shadowghost
f49a051a5f Respect timestamps when extracting subtitles 2022-08-02 13:21:10 +02:00
Joshua Boniface
5bcab0f0f8 Restore "Merge pull request #8087 from cvium/generic_subtitleparser"
After tagging v10.8.3, this can be restored to how it was and corrected
as required in a separate PR.

This reverts commit 494ed7e4d2.
2022-08-01 20:40:54 -04:00
Luke F
3bd2cc9860 Resolve a System.IndexOutOfRangeException when requesting IDs that do not exist via /Users/.../Items. Previously it was possible for the 'index' values in 'positions' to refer beyond 'size'.
[ERR] Error processing request. URL "GET" "/Users/.../Items".
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at MediaBrowser.Controller.Entities.Folder.SortItemsByRequest(InternalItemsQuery query, IReadOnlyList`1 items)
   at MediaBrowser.Controller.Entities.Folder.GetItems(InternalItemsQuery query)
   at Jellyfin.Api.Controllers.ItemsController.GetItems
2022-07-29 20:43:38 +01:00
Shadowghost
feb035b9e0 Extract external subs from container before determining character set 2022-07-27 10:08:53 +02:00
93 changed files with 1200 additions and 342 deletions

View File

@@ -36,6 +36,7 @@
- [dmitrylyzo](https://github.com/dmitrylyzo)
- [DMouse10462](https://github.com/DMouse10462)
- [DrPandemic](https://github.com/DrPandemic)
- [eglia](https://github.com/eglia)
- [EraYaN](https://github.com/EraYaN)
- [escabe](https://github.com/escabe)
- [excelite](https://github.com/excelite)
@@ -157,6 +158,7 @@
- [jonas-resch](https://github.com/jonas-resch)
- [vgambier](https://github.com/vgambier)
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
- [RealGreenDragon](https://github.com/RealGreenDragon)
# Emby Contributors

View File

@@ -72,7 +72,7 @@ COPY . .
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 -p:DebugSymbols=false -p:DebugType=none
FROM app

View File

@@ -64,7 +64,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm -p:DebugSymbols=false -p:DebugType=none
FROM app

View File

@@ -55,7 +55,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 -p:DebugSymbols=false -p:DebugType=none
FROM app

View File

@@ -36,7 +36,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -15,7 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="TagLibSharp" Version="2.2.0" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
</ItemGroup>
<PropertyGroup>

View File

@@ -1088,15 +1088,7 @@ namespace Emby.Server.Implementations
return GetLocalApiUrl(request.Host.Host, request.Scheme, requestPort);
}
// Published server ends with a /
if (!string.IsNullOrEmpty(PublishedServerUrl))
{
// Published server ends with a '/', so we need to remove it.
return PublishedServerUrl.Trim('/');
}
string smart = NetManager.GetBindInterface(request, out var port);
return GetLocalApiUrl(smart.Trim('/'), request.Scheme, port);
return GetSmartApiUrl(request.HttpContext.Connection.RemoteIpAddress ?? IPAddress.Loopback);
}
/// <inheritdoc/>

View File

@@ -3541,6 +3541,13 @@ namespace Emby.Server.Implementations.Data
statement?.TryBind("@MinIndexNumber", query.MinIndexNumber.Value);
}
if (query.MinParentAndIndexNumber.HasValue)
{
whereClauses.Add("((ParentIndexNumber=@MinParentAndIndexNumberParent and IndexNumber>=@MinParentAndIndexNumberIndex) or ParentIndexNumber>@MinParentAndIndexNumberParent)");
statement?.TryBind("@MinParentAndIndexNumberParent", query.MinParentAndIndexNumber.Value.ParentIndexNumber);
statement?.TryBind("@MinParentAndIndexNumberIndex", query.MinParentAndIndexNumber.Value.IndexNumber);
}
if (query.MinDateCreated.HasValue)
{
whereClauses.Add("DateCreated>=@MinDateCreated");

View File

@@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.People))
{
AttachPeople(dto, item);
AttachPeople(dto, item, user);
}
if (options.ContainsField(ItemFields.PrimaryImageAspectRatio))
@@ -503,7 +503,8 @@ namespace Emby.Server.Implementations.Dto
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item)
/// <param name="user">The requesting user.</param>
private void AttachPeople(BaseItemDto dto, BaseItem item, User user = null)
{
// Ordering by person type to ensure actors and artists are at the front.
// This is taking advantage of the fact that they both begin with A
@@ -560,6 +561,9 @@ namespace Emby.Server.Implementations.Dto
return null;
}
}).Where(i => i != null)
.Where(i => user == null ?
true :
i.IsVisible(user))
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);

View File

@@ -29,10 +29,10 @@
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.9" />
<PackageReference Include="Mono.Nat" Version="3.0.3" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.4" />
<PackageReference Include="sharpcompress" Version="0.32.1" />
<PackageReference Include="sharpcompress" Version="0.32.2" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
</ItemGroup>

View File

@@ -2766,7 +2766,8 @@ namespace Emby.Server.Implementations.Library
public List<Person> GetPeopleItems(InternalPeopleQuery query)
{
return _itemRepository.GetPeopleNames(query).Select(i =>
return _itemRepository.GetPeopleNames(query)
.Select(i =>
{
try
{
@@ -2777,7 +2778,12 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person");
return null;
}
}).Where(i => i != null).ToList();
})
.Where(i => i != null)
.Where(i => query.User == null ?
true :
i.IsVisible(query.User))
.ToList();
}
public List<string> GetPeopleNames(InternalPeopleQuery query)

View File

@@ -165,12 +165,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
const double DesiredAspect = 2.0 / 3;
programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, DesiredAspect) ??
GetProgramImage(ApiUrl, allImages, DesiredAspect);
programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, DesiredAspect, token) ??
GetProgramImage(ApiUrl, allImages, DesiredAspect, token);
const double WideAspect = 16.0 / 9;
programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, WideAspect);
programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, WideAspect, token);
// Don't supply the same image twice
if (string.Equals(programEntry.PrimaryImage, programEntry.ThumbImage, StringComparison.Ordinal))
@@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
programEntry.ThumbImage = null;
}
programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, WideAspect);
programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, WideAspect, token);
// programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
@@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return info;
}
private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> images, double desiredAspect)
private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> images, double desiredAspect, string token)
{
var match = images
.OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i)))
@@ -423,7 +423,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
else
{
return apiUrl + "/image/" + uri;
return apiUrl + "/image/" + uri + "?token=" + token;
}
}
@@ -457,6 +457,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
IReadOnlyList<string> programIds,
CancellationToken cancellationToken)
{
var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
if (programIds.Count == 0)
{
return Array.Empty<ShowImagesDto>();
@@ -478,6 +480,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
Content = new StringContent(str.ToString(), Encoding.UTF8, MediaTypeNames.Application.Json)
};
message.Headers.TryAddWithoutValidation("token", token);
try
{

View File

@@ -386,6 +386,7 @@ namespace Emby.Server.Implementations.Localization
yield return new LocalizationOption("Español (Dominicana)", "es_DO");
yield return new LocalizationOption("Español (México)", "es-MX");
yield return new LocalizationOption("Eesti", "et");
yield return new LocalizationOption("Basque", "eu");
yield return new LocalizationOption("فارسی", "fa");
yield return new LocalizationOption("Suomi", "fi");
yield return new LocalizationOption("Filipino", "fil");

View File

@@ -135,20 +135,15 @@ namespace Emby.Server.Implementations.TV
return GetResult(episodes, request);
}
public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IReadOnlyList<string> seriesKeys, DtoOptions dtoOptions)
private IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IReadOnlyList<string> seriesKeys, DtoOptions dtoOptions)
{
// Avoid implicitly captured closure
var currentUser = user;
var allNextUp = seriesKeys
.Select(i => GetNextUp(i, currentUser, dtoOptions, false));
var allNextUp = seriesKeys.Select(i => GetNextUp(i, user, dtoOptions, false));
if (request.EnableRewatching)
{
allNextUp = allNextUp.Concat(
seriesKeys.Select(i => GetNextUp(i, currentUser, dtoOptions, true))
)
.OrderByDescending(i => i.Item1);
seriesKeys.Select(i => GetNextUp(i, user, dtoOptions, true)))
.OrderByDescending(i => i.LastWatchedDate);
}
// If viewing all next up for all series, remove first episodes
@@ -161,23 +156,18 @@ namespace Emby.Server.Implementations.TV
{
if (request.DisableFirstEpisode)
{
return i.Item1 != DateTime.MinValue;
return i.LastWatchedDate != DateTime.MinValue;
}
if (alwaysEnableFirstEpisode || (i.Item1 != DateTime.MinValue && i.Item1.Date >= request.NextUpDateCutoff))
if (alwaysEnableFirstEpisode || (i.LastWatchedDate != DateTime.MinValue && i.LastWatchedDate.Date >= request.NextUpDateCutoff))
{
anyFound = true;
return true;
}
if (!anyFound && i.Item1 == DateTime.MinValue)
{
return true;
}
return false;
return !anyFound && i.LastWatchedDate == DateTime.MinValue;
})
.Select(i => i.Item2())
.Select(i => i.GetEpisodeFunction())
.Where(i => i != null);
}
@@ -195,14 +185,13 @@ namespace Emby.Server.Implementations.TV
/// Gets the next up.
/// </summary>
/// <returns>Task{Episode}.</returns>
private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions, bool rewatching)
private (DateTime LastWatchedDate, Func<Episode> GetEpisodeFunction) GetNextUp(string seriesKey, User user, DtoOptions dtoOptions, bool rewatching)
{
var lastQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Descending) },
IsPlayed = true,
Limit = 1,
ParentIndexNumberNotEquals = 0,
@@ -213,42 +202,38 @@ namespace Emby.Server.Implementations.TV
}
};
if (rewatching)
{
// find last watched by date played, not by newest episode watched
lastQuery.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) };
}
// If rewatching is enabled, sort first by date played and then by season and episode numbers
lastQuery.OrderBy = rewatching
? new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) }
: new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Descending), (ItemSortBy.IndexNumber, SortOrder.Descending) };
var lastWatchedEpisode = _libraryManager.GetItemList(lastQuery).Cast<Episode>().FirstOrDefault();
Func<Episode> getEpisode = () =>
Episode GetEpisode()
{
var nextQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
OrderBy = new[] { (ItemSortBy.ParentIndexNumber, SortOrder.Ascending), (ItemSortBy.IndexNumber, SortOrder.Ascending) },
Limit = 1,
IsPlayed = rewatching,
IsVirtualItem = false,
ParentIndexNumberNotEquals = 0,
MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
};
Episode nextEpisode;
if (rewatching)
// Locate the next up episode based on the last watched episode's season and episode number
var lastWatchedParentIndexNumber = lastWatchedEpisode?.ParentIndexNumber;
var lastWatchedIndexNumber = lastWatchedEpisode?.IndexNumberEnd ?? lastWatchedEpisode?.IndexNumber;
if (lastWatchedParentIndexNumber.HasValue && lastWatchedIndexNumber.HasValue)
{
nextQuery.Limit = 2;
// get watched episode after most recently watched
nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().ElementAtOrDefault(1);
}
else
{
nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().FirstOrDefault();
nextQuery.MinParentAndIndexNumber = (lastWatchedParentIndexNumber.Value, lastWatchedIndexNumber.Value + 1);
}
var nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().FirstOrDefault();
if (_configurationManager.Configuration.DisplaySpecialsWithinSeasons)
{
var consideredEpisodes = _libraryManager.GetItemList(new InternalItemsQuery(user)
@@ -297,7 +282,7 @@ namespace Emby.Server.Implementations.TV
}
return nextEpisode;
};
}
if (lastWatchedEpisode != null)
{
@@ -305,11 +290,11 @@ namespace Emby.Server.Implementations.TV
var lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue.AddDays(1);
return new Tuple<DateTime, Func<Episode>>(lastWatchedDate, getEpisode);
return (lastWatchedDate, GetEpisode);
}
// Return the first episode
return new Tuple<DateTime, Func<Episode>>(DateTime.MinValue, getEpisode);
return (DateTime.MinValue, GetEpisode);
}
private static QueryResult<BaseItem> GetResult(IEnumerable<BaseItem> items, NextUpQuery query)

View File

@@ -270,30 +270,13 @@ namespace Jellyfin.Api.Controllers
includeItemTypes = new[] { BaseItemKind.Playlist };
}
var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels);
bool isInEnabledFolder = Array.IndexOf(user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders), item.Id) != -1
// Assume all folders inside an EnabledChannel are enabled
|| Array.IndexOf(enabledChannels, item.Id) != -1
// Assume all items inside an EnabledChannel are enabled
|| Array.IndexOf(enabledChannels, item.ChannelId) != -1;
var collectionFolders = _libraryManager.GetCollectionFolders(item);
foreach (var collectionFolder in collectionFolders)
{
if (user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(collectionFolder.Id))
{
isInEnabledFolder = true;
}
}
if (item is not UserRootFolder
&& !isInEnabledFolder
&& !user.HasPermission(PermissionKind.EnableAllFolders)
&& !user.HasPermission(PermissionKind.EnableAllChannels)
&& !string.Equals(collectionType, CollectionType.Folders, StringComparison.OrdinalIgnoreCase))
// api keys can always access all folders
&& !ClaimHelpers.GetIsApiKey(User)
// check the item is visible for the user
&& !item.IsVisible(user))
{
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
_logger.LogWarning("{UserName} is not permitted to access Library {ItemName}", user!.Username, item.Name);
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
}

View File

@@ -492,7 +492,7 @@ namespace Jellyfin.Api.Controllers
/// <response code="200">Media folders returned.</response>
/// <returns>List of user media folders.</returns>
[HttpGet("Library/MediaFolders")]
[Authorize(Policy = Policies.DefaultAuthorization)]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult<QueryResult<BaseItemDto>> GetMediaFolders([FromQuery] bool? isHidden)
{

View File

@@ -98,7 +98,10 @@ namespace Jellyfin.Api.Controllers
Limit = limit ?? 0
});
return new QueryResult<BaseItemDto>(peopleItems.Select(person => _dtoService.GetItemByNameDto(person, dtoOptions, null, user)).ToArray());
return new QueryResult<BaseItemDto>(
peopleItems
.Select(person => _dtoService.GetItemByNameDto(person, dtoOptions, null, user))
.ToArray());
}
/// <summary>

View File

@@ -117,7 +117,13 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool enableRedirection = true)
{
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
(await _authorizationContext.GetAuthorizationInfo(Request).ConfigureAwait(false)).DeviceId = deviceId;
var authorizationInfo = await _authorizationContext.GetAuthorizationInfo(Request).ConfigureAwait(false);
authorizationInfo.DeviceId = deviceId;
if (!userId.HasValue || userId.Value.Equals(Guid.Empty))
{
userId = authorizationInfo.UserId;
}
var authInfo = await _authorizationContext.GetAuthorizationInfo(Request).ConfigureAwait(false);

View File

@@ -654,7 +654,7 @@ namespace Jellyfin.Api.Helpers
{
if (EnableThrottling(state))
{
transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger<TranscodingThrottler>(new LoggerFactory()), _serverConfigurationManager, _fileSystem);
transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger<TranscodingThrottler>(new LoggerFactory()), _serverConfigurationManager, _fileSystem, _mediaEncoder);
transcodingJob.TranscodingThrottler.Start();
}
}

View File

@@ -17,7 +17,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.3.1" />

View File

@@ -2,6 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -17,6 +18,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
private readonly ILogger<TranscodingThrottler> _logger;
private readonly IConfigurationManager _config;
private readonly IFileSystem _fileSystem;
private readonly IMediaEncoder _mediaEncoder;
private Timer? _timer;
private bool _isPaused;
@@ -27,12 +29,14 @@ namespace Jellyfin.Api.Models.PlaybackDtos
/// <param name="logger">Instance of the <see cref="ILogger{TranscodingThrottler}"/> interface.</param>
/// <param name="config">Instance of the <see cref="IConfigurationManager"/> interface.</param>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
public TranscodingThrottler(TranscodingJobDto job, ILogger<TranscodingThrottler> logger, IConfigurationManager config, IFileSystem fileSystem)
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
public TranscodingThrottler(TranscodingJobDto job, ILogger<TranscodingThrottler> logger, IConfigurationManager config, IFileSystem fileSystem, IMediaEncoder mediaEncoder)
{
_job = job;
_logger = logger;
_config = config;
_fileSystem = fileSystem;
_mediaEncoder = mediaEncoder;
}
/// <summary>
@@ -55,7 +59,8 @@ namespace Jellyfin.Api.Models.PlaybackDtos
try
{
await _job.Process!.StandardInput.WriteLineAsync().ConfigureAwait(false);
var resumeKey = _mediaEncoder.IsPkeyPauseSupported ? "u" : Environment.NewLine;
await _job.Process!.StandardInput.WriteAsync(resumeKey).ConfigureAwait(false);
_isPaused = false;
}
catch (Exception ex)
@@ -125,11 +130,13 @@ namespace Jellyfin.Api.Models.PlaybackDtos
{
if (!_isPaused)
{
_logger.LogDebug("Sending pause command to ffmpeg");
var pauseKey = _mediaEncoder.IsPkeyPauseSupported ? "p" : "c";
_logger.LogDebug("Sending pause command [{Key}] to ffmpeg", pauseKey);
try
{
await _job.Process!.StandardInput.WriteAsync("c").ConfigureAwait(false);
await _job.Process!.StandardInput.WriteAsync(pauseKey).ConfigureAwait(false);
_isPaused = true;
}
catch (Exception ex)

View File

@@ -18,7 +18,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -18,8 +18,8 @@
<ItemGroup>
<PackageReference Include="BlurHashSharp" Version="1.2.0" />
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.2.0" />
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.79" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.79" />
<PackageReference Include="SkiaSharp" Version="2.88.2" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.2" />
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
</ItemGroup>

View File

@@ -27,13 +27,13 @@
<ItemGroup>
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.7">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.7">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -0,0 +1,657 @@
#pragma warning disable CS1591
// <auto-generated />
using System;
using Jellyfin.Server.Implementations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Jellyfin.Server.Implementations.Migrations
{
[DbContext(typeof(JellyfinDb))]
[Migration("20221022080052_AddIndexActivityLogsDateCreated")]
partial class AddIndexActivityLogsDateCreated
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("jellyfin")
.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<double>("EndHour")
.HasColumnType("REAL");
b.Property<double>("StartHour")
.HasColumnType("REAL");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccessSchedules", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("DateCreated")
.HasColumnType("TEXT");
b.Property<string>("ItemId")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<int>("LogSeverity")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("Overview")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<string>("ShortOverview")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DateCreated");
b.ToTable("ActivityLogs", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "ItemId", "Client", "Key")
.IsUnique();
b.ToTable("CustomItemDisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("ChromecastVersion")
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<string>("DashboardTheme")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<bool>("EnableNextVideoInfoOverlay")
.HasColumnType("INTEGER");
b.Property<int?>("IndexBy")
.HasColumnType("INTEGER");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<int>("ScrollDirection")
.HasColumnType("INTEGER");
b.Property<bool>("ShowBackdrop")
.HasColumnType("INTEGER");
b.Property<bool>("ShowSidebar")
.HasColumnType("INTEGER");
b.Property<int>("SkipBackwardLength")
.HasColumnType("INTEGER");
b.Property<int>("SkipForwardLength")
.HasColumnType("INTEGER");
b.Property<string>("TvHome")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "ItemId", "Client")
.IsUnique();
b.ToTable("DisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DisplayPreferencesId")
.HasColumnType("INTEGER");
b.Property<int>("Order")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DisplayPreferencesId");
b.ToTable("HomeSection", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("LastModified")
.HasColumnType("TEXT");
b.Property<string>("Path")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("ImageInfos", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<int?>("IndexBy")
.HasColumnType("INTEGER");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<bool>("RememberIndexing")
.HasColumnType("INTEGER");
b.Property<bool>("RememberSorting")
.HasColumnType("INTEGER");
b.Property<string>("SortBy")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.Property<int>("SortOrder")
.HasColumnType("INTEGER");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<int>("ViewType")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemDisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Kind")
.HasColumnType("INTEGER");
b.Property<Guid?>("Permission_Permissions_Guid")
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<bool>("Value")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Permissions", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Kind")
.HasColumnType("INTEGER");
b.Property<Guid?>("Preference_Preferences_Guid")
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Preferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AccessToken")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("DateCreated")
.HasColumnType("TEXT");
b.Property<DateTime>("DateLastActivity")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("AccessToken")
.IsUnique();
b.ToTable("ApiKeys", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AccessToken")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("AppName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.Property<string>("AppVersion")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<DateTime>("DateCreated")
.HasColumnType("TEXT");
b.Property<DateTime>("DateLastActivity")
.HasColumnType("TEXT");
b.Property<DateTime>("DateModified")
.HasColumnType("TEXT");
b.Property<string>("DeviceId")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("DeviceName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.Property<bool>("IsActive")
.HasColumnType("INTEGER");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeviceId");
b.HasIndex("AccessToken", "DateLastActivity");
b.HasIndex("DeviceId", "DateLastActivity");
b.HasIndex("UserId", "DeviceId");
b.ToTable("Devices", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("CustomName")
.HasColumnType("TEXT");
b.Property<string>("DeviceId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("DeviceId")
.IsUnique();
b.ToTable("DeviceOptions", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("AudioLanguagePreference")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<string>("AuthenticationProviderId")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<bool>("DisplayCollectionsView")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayMissingEpisodes")
.HasColumnType("INTEGER");
b.Property<string>("EasyPassword")
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.Property<bool>("EnableAutoLogin")
.HasColumnType("INTEGER");
b.Property<bool>("EnableLocalPassword")
.HasColumnType("INTEGER");
b.Property<bool>("EnableNextEpisodeAutoPlay")
.HasColumnType("INTEGER");
b.Property<bool>("EnableUserPreferenceAccess")
.HasColumnType("INTEGER");
b.Property<bool>("HidePlayedInLatest")
.HasColumnType("INTEGER");
b.Property<long>("InternalId")
.HasColumnType("INTEGER");
b.Property<int>("InvalidLoginAttemptCount")
.HasColumnType("INTEGER");
b.Property<DateTime?>("LastActivityDate")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastLoginDate")
.HasColumnType("TEXT");
b.Property<int?>("LoginAttemptsBeforeLockout")
.HasColumnType("INTEGER");
b.Property<int>("MaxActiveSessions")
.HasColumnType("INTEGER");
b.Property<int?>("MaxParentalAgeRating")
.HasColumnType("INTEGER");
b.Property<bool>("MustUpdatePassword")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.Property<string>("PasswordResetProviderId")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<bool>("PlayDefaultAudioTrack")
.HasColumnType("INTEGER");
b.Property<bool>("RememberAudioSelections")
.HasColumnType("INTEGER");
b.Property<bool>("RememberSubtitleSelections")
.HasColumnType("INTEGER");
b.Property<int?>("RemoteClientBitrateLimit")
.HasColumnType("INTEGER");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<string>("SubtitleLanguagePreference")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<int>("SubtitleMode")
.HasColumnType("INTEGER");
b.Property<int>("SyncPlayAccess")
.HasColumnType("INTEGER");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.HasKey("Id");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Users", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("AccessSchedules")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("DisplayPreferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
{
b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
.WithMany("HomeSections")
.HasForeignKey("DisplayPreferencesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithOne("ProfileImage")
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("ItemDisplayPreferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Permissions")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Preferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.Navigation("HomeSections");
});
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
{
b.Navigation("AccessSchedules");
b.Navigation("DisplayPreferences");
b.Navigation("ItemDisplayPreferences");
b.Navigation("Permissions");
b.Navigation("Preferences");
b.Navigation("ProfileImage");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,28 @@
#pragma warning disable CS1591, SA1601
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Jellyfin.Server.Implementations.Migrations
{
public partial class AddIndexActivityLogsDateCreated : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_ActivityLogs_DateCreated",
schema: "jellyfin",
table: "ActivityLogs",
column: "DateCreated");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_ActivityLogs_DateCreated",
schema: "jellyfin",
table: "ActivityLogs");
}
}
}

View File

@@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Jellyfin.Server.Implementations.Migrations
{
[DbContext(typeof(JellyfinDb))]
@@ -15,7 +17,7 @@ namespace Jellyfin.Server.Implementations.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("jellyfin")
.HasAnnotation("ProductVersion", "5.0.7");
.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
@@ -39,7 +41,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId");
b.ToTable("AccessSchedules");
b.ToTable("AccessSchedules", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
@@ -85,7 +87,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
b.ToTable("ActivityLogs");
b.HasIndex("DateCreated");
b.ToTable("ActivityLogs", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
@@ -117,7 +121,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId", "ItemId", "Client", "Key")
.IsUnique();
b.ToTable("CustomItemDisplayPreferences");
b.ToTable("CustomItemDisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
@@ -174,7 +178,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId", "ItemId", "Client")
.IsUnique();
b.ToTable("DisplayPreferences");
b.ToTable("DisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
@@ -196,7 +200,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("DisplayPreferencesId");
b.ToTable("HomeSection");
b.ToTable("HomeSection", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
@@ -221,7 +225,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId")
.IsUnique();
b.ToTable("ImageInfos");
b.ToTable("ImageInfos", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
@@ -265,7 +269,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId");
b.ToTable("ItemDisplayPreferences");
b.ToTable("ItemDisplayPreferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
@@ -296,7 +300,7 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Permissions");
b.ToTable("Permissions", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
@@ -329,7 +333,7 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Preferences");
b.ToTable("Preferences", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b =>
@@ -358,7 +362,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("AccessToken")
.IsUnique();
b.ToTable("ApiKeys");
b.ToTable("ApiKeys", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b =>
@@ -416,7 +420,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("UserId", "DeviceId");
b.ToTable("Devices");
b.ToTable("Devices", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b =>
@@ -437,7 +441,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("DeviceId")
.IsUnique();
b.ToTable("DeviceOptions");
b.ToTable("DeviceOptions", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
@@ -550,7 +554,7 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasIndex("Username")
.IsUnique();
b.ToTable("Users");
b.ToTable("Users", "jellyfin");
});
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>

View File

@@ -0,0 +1,17 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// FluentAPI configuration for the ActivityLog entity.
/// </summary>
public class ActivityLogConfiguration : IEntityTypeConfiguration<ActivityLog>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<ActivityLog> builder)
{
builder.HasIndex(entity => entity.DateCreated);
}
}

View File

@@ -434,11 +434,15 @@ namespace Jellyfin.Server.Extensions
options.MapType<TranscodeReason>(() =>
new OpenApiSchema
{
Type = "string",
Enum = Enum.GetNames<TranscodeReason>()
.Select(e => new OpenApiString(e))
.Cast<IOpenApiAny>()
.ToArray()
Type = "array",
Items = new OpenApiSchema
{
Reference = new OpenApiReference
{
Id = nameof(TranscodeReason),
Type = ReferenceType.Schema,
}
}
});
// Swashbuckle doesn't use JsonOptions to describe responses, so we need to manually describe it.

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using Jellyfin.Extensions;
using Jellyfin.Server.Migrations;
using MediaBrowser.Common.Plugins;
@@ -8,6 +9,7 @@ using MediaBrowser.Model.ApiClient;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.SyncPlay;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
@@ -56,6 +58,15 @@ namespace Jellyfin.Server.Filters
context.SchemaGenerator.GenerateSchema(configuration.ConfigurationType, context.SchemaRepository);
}
context.SchemaRepository.AddDefinition(nameof(TranscodeReason), new OpenApiSchema
{
Type = "string",
Enum = Enum.GetNames<TranscodeReason>()
.Select(e => new OpenApiString(e))
.Cast<IOpenApiAny>()
.ToArray()
});
}
}
}

View File

@@ -37,8 +37,8 @@
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.7" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.7" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.9" />
<PackageReference Include="prometheus-net" Version="6.0.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -1863,7 +1863,7 @@ namespace MediaBrowser.Controller.Entities
data.PlaybackPositionTicks = 0;
}
data.LastPlayedDate = datePlayed ?? data.LastPlayedDate ?? DateTime.UtcNow;
data.LastPlayedDate = datePlayed ?? DateTime.UtcNow;
data.Played = true;
UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None);

View File

@@ -892,29 +892,7 @@ namespace MediaBrowser.Controller.Entities
private static BaseItem[] SortItemsByRequest(InternalItemsQuery query, IReadOnlyList<BaseItem> items)
{
var ids = query.ItemIds;
int size = items.Count;
// ids can potentially contain non-unique guids, but query result cannot,
// so we include only first occurrence of each guid
var positions = new Dictionary<Guid, int>(size);
int index = 0;
for (int i = 0; i < ids.Length; i++)
{
if (positions.TryAdd(ids[i], index))
{
index++;
}
}
var newItems = new BaseItem[size];
for (int i = 0; i < size; i++)
{
var item = items[i];
newItems[positions[item.Id]] = item;
}
return newItems;
return items.OrderBy(i => Array.IndexOf(query.ItemIds, i.Id)).ToArray();
}
public QueryResult<BaseItem> GetItems(InternalItemsQuery query)

View File

@@ -205,6 +205,16 @@ namespace MediaBrowser.Controller.Entities
public int? MinIndexNumber { get; set; }
/// <summary>
/// Gets or sets the minimum ParentIndexNumber and IndexNumber.
/// </summary>
/// <remarks>
/// It produces this where clause:
/// <para>(ParentIndexNumber = X and IndexNumber >= Y) or ParentIndexNumber > X.
/// </para>
/// </remarks>
public (int ParentIndexNumber, int IndexNumber)? MinParentAndIndexNumber { get; set; }
public int? AiredDuringSeason { get; set; }
public double? MinCriticRating { get; set; }

View File

@@ -258,10 +258,14 @@ namespace MediaBrowser.Controller.Entities.TV
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options,
IsMissing = user?.DisplayMissingEpisodes
DtoOptions = options
};
if (user == null || !user.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
var allItems = LibraryManager.GetItemList(query);
var allSeriesEpisodes = allItems.OfType<Episode>().ToList();

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -1152,16 +1152,15 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.SubtitleStream.IsExternal)
{
var subtitlePath = state.SubtitleStream.Path;
var charsetParam = string.Empty;
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
{
var charenc = _subtitleEncoder.GetSubtitleFileCharacterSet(
subtitlePath,
state.SubtitleStream.Language,
state.MediaSource.Protocol,
CancellationToken.None).GetAwaiter().GetResult();
state.SubtitleStream,
state.SubtitleStream.Language,
state.MediaSource,
CancellationToken.None).GetAwaiter().GetResult();
if (!string.IsNullOrEmpty(charenc))
{
@@ -1173,7 +1172,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format(
CultureInfo.InvariantCulture,
"subtitles=f='{0}'{1}{2}{3}{4}{5}",
_mediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
_mediaEncoder.EscapeSubtitleFilterPath(state.SubtitleStream.Path),
charsetParam,
alphaParam,
sub2videoParam,
@@ -1416,7 +1415,11 @@ namespace MediaBrowser.Controller.MediaEncoding
param += " -preset 7";
}
param += " -look_ahead 0";
// Only h264_qsv has look_ahead option
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
param += " -look_ahead 0";
}
}
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
@@ -1454,7 +1457,7 @@ namespace MediaBrowser.Controller.MediaEncoding
break;
default:
param += " -preset p4";
param += " -preset p1";
break;
}
}
@@ -3405,6 +3408,12 @@ namespace MediaBrowser.Controller.MediaEncoding
// map from d3d11va to qsv.
mainFilters.Add("hwmap=derive_device=qsv");
}
else
{
// Insert a qsv scaler to sync the decoder surface,
// msdk will passthrough this internally.
mainFilters.Add("hwmap=derive_device=qsv,scale_qsv");
}
}
// hw deint
@@ -4977,14 +4986,14 @@ namespace MediaBrowser.Controller.MediaEncoding
// The default value of -probesize is more than enough, so leave it as is.
var ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDurationArgument = "-analyzeduration " + ffmpegAnalyzeDuration;
}
else if (state.MediaSource.AnalyzeDurationMs.HasValue)
if (state.MediaSource.AnalyzeDurationMs > 0)
{
analyzeDurationArgument = "-analyzeduration " + (state.MediaSource.AnalyzeDurationMs.Value * 1000).ToString(CultureInfo.InvariantCulture);
}
else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDurationArgument = "-analyzeduration " + ffmpegAnalyzeDuration;
}
if (!string.IsNullOrEmpty(analyzeDurationArgument))
{
@@ -5536,7 +5545,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return index;
}
if (string.Equals(currentMediaStream.Path, streamToFind.Path, StringComparison.Ordinal))
if (string.Equals(currentMediaStream.Path, streamToFind.Path, StringComparison.Ordinal))
{
index++;
}

View File

@@ -37,6 +37,12 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns>The version of encoder.</returns>
Version EncoderVersion { get; }
/// <summary>
/// Whether p key pausing is supported.
/// </summary>
/// <value><c>true</c> if p key pausing is supported, <c>false</c> otherwise.</value>
bool IsPkeyPauseSupported { get; }
/// <summary>
/// Gets a value indicating whether the configured Vaapi device is from AMD(radeonsi/r600 Mesa driver).
/// </summary>

View File

@@ -6,7 +6,8 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -37,11 +38,11 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the subtitle language encoding parameter.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="subtitleStream">The subtitle stream.</param>
/// <param name="language">The language.</param>
/// <param name="protocol">The protocol.</param>
/// <param name="mediaSource">The media source.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>System.String.</returns>
Task<string> GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken);
Task<string> GetSubtitleFileCharacterSet(MediaStream subtitleStream, string language, MediaSourceInfo mediaSource, CancellationToken cancellationToken);
}
}

View File

@@ -153,7 +153,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string output;
try
{
output = GetProcessOutput(_encoderPath, "-version", false);
output = GetProcessOutput(_encoderPath, "-version", false, null);
}
catch (Exception ex)
{
@@ -234,7 +234,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string output;
try
{
output = GetProcessOutput(_encoderPath, "-version", false);
output = GetProcessOutput(_encoderPath, "-version", false, null);
}
catch (Exception ex)
{
@@ -341,7 +341,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
try
{
var output = GetProcessOutput(_encoderPath, "-v verbose -hide_banner -init_hw_device vaapi=va:" + renderNodePath, true);
var output = GetProcessOutput(_encoderPath, "-v verbose -hide_banner -init_hw_device vaapi=va:" + renderNodePath, true, null);
return output.Contains(driverName, StringComparison.Ordinal);
}
catch (Exception ex)
@@ -356,7 +356,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string? output = null;
try
{
output = GetProcessOutput(_encoderPath, "-hwaccels", false);
output = GetProcessOutput(_encoderPath, "-hwaccels", false, null);
}
catch (Exception ex)
{
@@ -384,7 +384,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string output;
try
{
output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false);
output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false, null);
}
catch (Exception ex)
{
@@ -402,13 +402,34 @@ namespace MediaBrowser.MediaEncoding.Encoder
return false;
}
public bool CheckSupportedRuntimeKey(string keyDesc)
{
if (string.IsNullOrEmpty(keyDesc))
{
return false;
}
string output;
try
{
output = GetProcessOutput(_encoderPath, "-hide_banner -f lavfi -i nullsrc=s=1x1:d=500 -f null -", true, "?");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error checking supported runtime key");
return false;
}
return output.Contains(keyDesc, StringComparison.Ordinal);
}
private IEnumerable<string> GetCodecs(Codec codec)
{
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
string output;
try
{
output = GetProcessOutput(_encoderPath, "-" + codecstr, false);
output = GetProcessOutput(_encoderPath, "-" + codecstr, false, null);
}
catch (Exception ex)
{
@@ -439,7 +460,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string output;
try
{
output = GetProcessOutput(_encoderPath, "-filters", false);
output = GetProcessOutput(_encoderPath, "-filters", false, null);
}
catch (Exception ex)
{
@@ -477,7 +498,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
return dict;
}
private string GetProcessOutput(string path, string arguments, bool readStdErr)
private string GetProcessOutput(string path, string arguments, bool readStdErr, string? testKey)
{
using (var process = new Process()
{
@@ -487,6 +508,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false,
RedirectStandardInput = !string.IsNullOrEmpty(testKey),
RedirectStandardOutput = true,
RedirectStandardError = true
}
@@ -496,6 +518,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
process.Start();
if (!string.IsNullOrEmpty(testKey))
{
process.StandardInput.Write(testKey);
}
return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
}
}

View File

@@ -67,6 +67,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
private List<string> _filters = new List<string>();
private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
private bool _isPkeyPauseSupported = false;
private bool _isVaapiDeviceAmd = false;
private bool _isVaapiDeviceInteliHD = false;
private bool _isVaapiDeviceInteli965 = false;
@@ -100,6 +102,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Version EncoderVersion => _ffmpegVersion;
public bool IsPkeyPauseSupported => _isPkeyPauseSupported;
public bool IsVaapiDeviceAmd => _isVaapiDeviceAmd;
public bool IsVaapiDeviceInteliHD => _isVaapiDeviceInteliHD;
@@ -154,6 +158,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
_threads = EncodingHelper.GetNumberOfThreads(null, options, null);
_isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding");
// Check the Vaapi device vendor
if (OperatingSystem.IsLinux()
&& SupportsHwaccel("vaapi")
@@ -376,15 +382,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
string analyzeDuration = string.Empty;
string ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDuration = "-analyzeduration " + ffmpegAnalyzeDuration;
}
else if (request.MediaSource.AnalyzeDurationMs > 0)
if (request.MediaSource.AnalyzeDurationMs > 0)
{
analyzeDuration = "-analyzeduration " +
(request.MediaSource.AnalyzeDurationMs * 1000).ToString();
}
else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDuration = "-analyzeduration " + ffmpegAnalyzeDuration;
}
var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File;

View File

@@ -863,8 +863,13 @@ namespace MediaBrowser.MediaEncoding.Probing
}
}
}
else if (string.Equals(streamInfo.CodecType, "data", StringComparison.OrdinalIgnoreCase))
{
stream.Type = MediaStreamType.Data;
}
else
{
_logger.LogError("Codec Type {CodecType} unknown. The stream (index: {Index}) will be ignored. Warning: Subsequential streams will have a wrong stream specifier!", streamInfo.CodecType, streamInfo.Index);
return null;
}

View File

@@ -238,7 +238,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
// Convert
var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, ".srt");
await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
await ConvertTextSubtitleToSrt(subtitleStream, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true);
}
@@ -351,13 +351,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <summary>
/// Converts the text subtitle to SRT.
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param>
/// <param name="subtitleStream">The subtitle stream.</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, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
private async Task ConvertTextSubtitleToSrt(MediaStream subtitleStream, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{
var semaphore = GetLock(outputPath);
@@ -367,7 +366,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
if (!File.Exists(outputPath))
{
await ConvertTextSubtitleToSrtInternal(inputPath, language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
await ConvertTextSubtitleToSrtInternal(subtitleStream, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -379,8 +378,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <summary>
/// Converts the text subtitle to SRT internal.
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param>
/// <param name="subtitleStream">The subtitle stream.</param>
/// <param name="mediaSource">The input mediaSource.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
@@ -388,8 +386,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <exception cref="ArgumentNullException">
/// The <c>inputPath</c> or <c>outputPath</c> is <c>null</c>.
/// </exception>
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
private async Task ConvertTextSubtitleToSrtInternal(MediaStream subtitleStream, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{
var inputPath = subtitleStream.Path;
if (string.IsNullOrEmpty(inputPath))
{
throw new ArgumentNullException(nameof(inputPath));
@@ -402,7 +401,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath)));
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, mediaSource.Protocol, cancellationToken).ConfigureAwait(false);
var encodingParam = await GetSubtitleFileCharacterSet(subtitleStream, subtitleStream.Language, mediaSource, 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"
@@ -420,18 +419,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
int exitCode;
using (var process = new Process
{
StartInfo = new ProcessStartInfo
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath,
Arguments = string.Format(CultureInfo.InvariantCulture, "{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
EnableRaisingEvents = true
})
CreateNoWindow = true,
UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath,
Arguments = string.Format(CultureInfo.InvariantCulture, "{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
EnableRaisingEvents = true
})
{
_logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
@@ -571,7 +570,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var processArgs = string.Format(
CultureInfo.InvariantCulture,
"-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"",
"-i {0} -copyts -map 0:{1} -an -vn -c:s {2} \"{3}\"",
inputPath,
subtitleStreamIndex,
outputCodec,
@@ -580,18 +579,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
int exitCode;
using (var process = new Process
{
StartInfo = new ProcessStartInfo
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath,
Arguments = processArgs,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
EnableRaisingEvents = true
})
CreateNoWindow = true,
UseShellExecute = false,
FileName = _mediaEncoder.EncoderPath,
Arguments = processArgs,
WindowStyle = ProcessWindowStyle.Hidden,
ErrorDialog = false
},
EnableRaisingEvents = true
})
{
_logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments);
@@ -606,7 +605,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
throw;
}
var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
var ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMinutes(30)).ConfigureAwait(false);
if (!ranToCompletion)
{
@@ -729,9 +728,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
/// <inheritdoc />
public async Task<string> GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken)
public async Task<string> GetSubtitleFileCharacterSet(MediaStream subtitleStream, string language, MediaSourceInfo mediaSource, CancellationToken cancellationToken)
{
using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
var subtitleCodec = subtitleStream.Codec;
var path = subtitleStream.Path;
if (path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase))
{
path = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + subtitleCodec);
await ExtractTextSubtitle(mediaSource, subtitleStream, subtitleCodec, path, cancellationToken)
.ConfigureAwait(false);
}
using (var stream = await GetStream(path, mediaSource.Protocol, cancellationToken).ConfigureAwait(false))
{
var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName ?? string.Empty;
@@ -754,12 +763,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
switch (protocol)
{
case MediaProtocol.Http:
{
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetAsync(new Uri(path), cancellationToken)
.ConfigureAwait(false);
return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
}
{
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetAsync(new Uri(path), cancellationToken)
.ConfigureAwait(false);
return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
}
case MediaProtocol.File:
return AsyncFile.OpenRead(path);

View File

@@ -436,9 +436,9 @@ namespace MediaBrowser.Model.Dlna
{
containerSupported = true;
videoSupported = videoStream != null && profile.SupportsVideoCodec(videoStream.Codec);
videoSupported = videoStream == null || profile.SupportsVideoCodec(videoStream.Codec);
audioSupported = audioStream != null && profile.SupportsAudioCodec(audioStream.Codec);
audioSupported = audioStream == null || profile.SupportsAudioCodec(audioStream.Codec);
if (videoSupported && audioSupported)
{
@@ -447,18 +447,17 @@ namespace MediaBrowser.Model.Dlna
}
}
var list = new List<TranscodeReason>();
if (!containerSupported)
{
reasons |= TranscodeReason.ContainerNotSupported;
}
if (videoStream != null && !videoSupported)
if (!videoSupported)
{
reasons |= TranscodeReason.VideoCodecNotSupported;
}
if (audioStream != null && !audioSupported)
if (!audioSupported)
{
reasons |= TranscodeReason.AudioCodecNotSupported;
}
@@ -590,21 +589,19 @@ namespace MediaBrowser.Model.Dlna
}
// Collect candidate audio streams
IEnumerable<MediaStream> candidateAudioStreams = audioStream == null ? Array.Empty<MediaStream>() : new[] { audioStream };
ICollection<MediaStream> candidateAudioStreams = audioStream == null ? Array.Empty<MediaStream>() : new[] { audioStream };
if (!options.AudioStreamIndex.HasValue || options.AudioStreamIndex < 0)
{
if (audioStream?.IsDefault == true)
{
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault);
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
}
else
{
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language);
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language).ToArray();
}
}
candidateAudioStreams = candidateAudioStreams.ToArray();
var videoStream = item.VideoStream;
var directPlayBitrateEligibility = IsBitrateEligibleForDirectPlayback(item, options.GetMaxBitrate(false) ?? 0, options, PlayMethod.DirectPlay);
@@ -1060,7 +1057,7 @@ namespace MediaBrowser.Model.Dlna
MediaSourceInfo mediaSource,
MediaStream videoStream,
MediaStream audioStream,
IEnumerable<MediaStream> candidateAudioStreams,
ICollection<MediaStream> candidateAudioStreams,
MediaStream subtitleStream,
bool isEligibleForDirectPlay,
bool isEligibleForDirectStream)
@@ -1182,14 +1179,18 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
var selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
if (selectedAudioStream == null)
MediaStream selectedAudioStream = null;
if (candidateAudioStreams.Any())
{
directPlayProfileReasons |= TranscodeReason.AudioCodecNotSupported;
}
else
{
audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream);
selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
if (selectedAudioStream == null)
{
directPlayProfileReasons |= TranscodeReason.AudioCodecNotSupported;
}
else
{
audioCodecProfileReasons = audioStreamMatches.GetValueOrDefault(selectedAudioStream);
}
}
var failureReasons = directPlayProfileReasons | containerProfileReasons | subtitleProfileReasons;

View File

@@ -594,6 +594,10 @@ namespace MediaBrowser.Model.Entities
<= 426 when Height <= 240 => IsInterlaced ? "240i" : "240p",
// 640x360 (16:9 square pixel format)
<= 640 when Height <= 360 => IsInterlaced ? "360i" : "360p",
// 682x384 (16:9 square pixel format)
<= 682 when Height <= 384 => IsInterlaced ? "384i" : "384p",
// 720x404 (16:9 square pixel format)
<= 720 when Height <= 404 => IsInterlaced ? "404i" : "404p",
// 854x480 (16:9 square pixel format)
<= 854 when Height <= 480 => IsInterlaced ? "480i" : "480p",
// 960x544 (16:9 square pixel format)

View File

@@ -23,6 +23,11 @@ namespace MediaBrowser.Model.Entities
/// <summary>
/// The embedded image.
/// </summary>
EmbeddedImage
EmbeddedImage,
/// <summary>
/// The data.
/// </summary>
Data
}
}

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@@ -34,13 +34,13 @@
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
<PackageReference Include="MimeTypes" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Globalization" Version="4.3.0" />
<PackageReference Include="System.Text.Json" Version="6.0.5" />
<PackageReference Include="System.Text.Json" Version="6.0.6" />
</ItemGroup>
<ItemGroup>

View File

@@ -408,10 +408,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
}
}
if (isEnglishRequested)
{
item.Overview = result.Plot;
}
item.Overview = result.Plot;
if (!Plugin.Instance.Configuration.CastAndCrew)
{

View File

@@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("10.8.3")]
[assembly: AssemblyFileVersion("10.8.3")]
[assembly: AssemblyVersion("10.8.8")]
[assembly: AssemblyFileVersion("10.8.8")]

View File

@@ -1,7 +1,7 @@
---
# We just wrap `build` so this is really it
name: "jellyfin"
version: "10.8.3"
version: "10.8.8"
packages:
- debian.amd64
- debian.arm64

30
debian/changelog vendored
View File

@@ -1,3 +1,33 @@
jellyfin-server (10.8.8-1) unstable; urgency=medium
* New upstream version 10.8.8; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.8
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 29 Nov 2022 13:42:47 -0500
jellyfin-server (10.8.7-1) unstable; urgency=medium
* New upstream version 10.8.7; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.7
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 31 Oct 2022 23:07:06 -0400
jellyfin-server (10.8.6-1) unstable; urgency=medium
* New upstream version 10.8.6; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.6
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 28 Oct 2022 22:41:01 -0400
jellyfin-server (10.8.5-1) unstable; urgency=medium
* New upstream version 10.8.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.5
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sat, 24 Sep 2022 22:01:56 -0400
jellyfin-server (10.8.4-1) unstable; urgency=medium
* New upstream version 10.8.4; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.4
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sat, 13 Aug 2022 21:51:45 -0400
jellyfin-server (10.8.3-1) unstable; urgency=medium
* New upstream version 10.8.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.3

View File

@@ -8,7 +8,7 @@ EnvironmentFile = /etc/default/jellyfin
User = jellyfin
Group = jellyfin
WorkingDirectory = /var/lib/jellyfin
ExecStart = /usr/bin/jellyfin ${JELLYFIN_WEB_OPT} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} ${JELLYFIN_ADDITIONAL_OPTS}
ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
Restart = on-failure
TimeoutSec = 15
SuccessExitStatus=0 143

View File

@@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
Standards-Version: 3.9.2
Package: jellyfin
Version: 10.8.3
Version: 10.8.8
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
Depends: jellyfin-server, jellyfin-web
Description: Provides the Jellyfin Free Software Media System

2
debian/rules vendored
View File

@@ -40,7 +40,7 @@ override_dh_clistrip:
override_dh_auto_build:
dotnet publish -maxcpucount:1 --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME) \
"-p:DebugSymbols=false;DebugType=none" Jellyfin.Server
-p:DebugSymbols=false -p:DebugType=none Jellyfin.Server
override_dh_auto_clean:
dotnet clean -maxcpucount:1 --configuration $(CONFIG) Jellyfin.Server || true

View File

@@ -13,7 +13,7 @@ RUN yum update -yq \
&& yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget
# Install DotNET SDK
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8159607a-e686-4ead-ac99-b4c97290a5fd/ec6070b1b2cc0651ebe57cf1bd411315/dotnet-sdk-6.0.401-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@@ -10,4 +10,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-x64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-x64 -p:DebugSymbols=false -p:DebugType=none

View File

@@ -10,4 +10,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm64 "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm64 -p:DebugSymbols=false -p:DebugType=none

View File

@@ -10,4 +10,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm "-p:DebugSymbols=false;DebugType=none"
RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm -p:DebugSymbols=false -p:DebugType=none

View File

@@ -12,7 +12,7 @@ RUN dnf update -yq \
&& dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget make
# Install DotNET SDK
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8159607a-e686-4ead-ac99-b4c97290a5fd/ec6070b1b2cc0651ebe57cf1bd411315/dotnet-sdk-6.0.401-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@@ -17,7 +17,7 @@ RUN apt-get update -yqq \
libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0
# Install dotnet repository
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8159607a-e686-4ead-ac99-b4c97290a5fd/ec6070b1b2cc0651ebe57cf1bd411315/dotnet-sdk-6.0.401-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@@ -16,7 +16,7 @@ RUN apt-get update -yqq \
mmv build-essential lsb-release
# Install dotnet repository
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8159607a-e686-4ead-ac99-b4c97290a5fd/ec6070b1b2cc0651ebe57cf1bd411315/dotnet-sdk-6.0.401-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@@ -16,7 +16,7 @@ RUN apt-get update -yqq \
mmv build-essential lsb-release
# Install dotnet repository
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/0e83f50a-0619-45e6-8f16-dc4f41d1bb16/e0de908b2f070ef9e7e3b6ddea9d268c/dotnet-sdk-6.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8159607a-e686-4ead-ac99-b4c97290a5fd/ec6070b1b2cc0651ebe57cf1bd411315/dotnet-sdk-6.0.401-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-x64 --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-x64 --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
tar -czf jellyfin-server_${version}_linux-amd64.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-musl-x64 --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-musl-x64 --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
tar -czf jellyfin-server_${version}_linux-amd64-musl.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-arm64 --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-arm64 --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
tar -czf jellyfin-server_${version}_linux-arm64.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-arm --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-arm --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
tar -czf jellyfin-server_${version}_linux-armhf.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime osx-x64 --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime osx-x64 --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
tar -czf jellyfin-server_${version}_macos-amd64.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -16,7 +16,7 @@ else
fi
# Build archives
dotnet publish Jellyfin.Server --configuration Release --output dist/jellyfin-server_${version}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=false"
dotnet publish Jellyfin.Server --configuration Release --output dist/jellyfin-server_${version}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=false
tar -czf jellyfin-server_${version}_portable.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}

View File

@@ -23,7 +23,7 @@ fi
output_dir="dist/jellyfin-server_${version}"
# Build binary
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime win-x64 --output ${output_dir}/ "-p:DebugSymbols=false;DebugType=none;UseAppHost=true"
dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime win-x64 --output ${output_dir}/ -p:DebugSymbols=false -p:DebugType=none -p:UseAppHost=true
# Prepare addins
addin_build_dir="$( mktemp -d )"

View File

@@ -5,3 +5,49 @@
[Service]
#User = jellyfin
#EnvironmentFile = /etc/sysconfig/jellyfin
# Service hardening options
# These were added in PR #6953 to solve issue #6952, but some combination of
# them causes "restart.sh" functionality to break with the following error:
# sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the
# 'nosuid' option set or an NFS file system without root privileges?
# See issue #7503 for details on the troubleshooting that went into this.
# Since these were added for NixOS specifically and are above and beyond
# what 99% of systemd units do, they have been moved here as optional
# additional flags to set for maximum system security and can be enabled at
# the administrator's or package maintainer's discretion.
# Uncomment these only if you know what you're doing, and doing so may cause
# bugs with in-server Restart and potentially other functionality as well.
#NoNewPrivileges=true
#SystemCallArchitectures=native
#RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
#RestrictNamespaces=false
#RestrictRealtime=true
#RestrictSUIDSGID=true
#ProtectClock=true
#ProtectControlGroups=false
#ProtectHostname=true
#ProtectKernelLogs=false
#ProtectKernelModules=false
#ProtectKernelTunables=false
#LockPersonality=true
#PrivateTmp=false
#PrivateDevices=false
#PrivateUsers=true
#RemoveIPC=true
#SystemCallFilter=~@clock
#SystemCallFilter=~@aio
#SystemCallFilter=~@chown
#SystemCallFilter=~@cpu-emulation
#SystemCallFilter=~@debug
#SystemCallFilter=~@keyring
#SystemCallFilter=~@memlock
#SystemCallFilter=~@module
#SystemCallFilter=~@mount
#SystemCallFilter=~@obsolete
#SystemCallFilter=~@privileged
#SystemCallFilter=~@raw-io
#SystemCallFilter=~@reboot
#SystemCallFilter=~@setuid
#SystemCallFilter=~@swap
#SystemCallErrorNumber=EPERM

View File

@@ -8,44 +8,10 @@ EnvironmentFile = /etc/sysconfig/jellyfin
User = jellyfin
Group = jellyfin
WorkingDirectory = /var/lib/jellyfin
ExecStart = /usr/bin/jellyfin ${JELLYFIN_WEB_OPT} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} ${JELLYFIN_ADDITIONAL_OPTS}
ExecStart = /usr/bin/jellyfin $JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT $JELLYFIN_ADDITIONAL_OPTS
Restart = on-failure
TimeoutSec = 15
SuccessExitStatus=0 143
NoNewPrivileges=true
SystemCallArchitectures=native
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=false
RestrictRealtime=true
RestrictSUIDSGID=true
ProtectClock=true
ProtectControlGroups=false
ProtectHostname=true
ProtectKernelLogs=false
ProtectKernelModules=false
ProtectKernelTunables=false
LockPersonality=true
PrivateTmp=false
PrivateDevices=false
PrivateUsers=true
RemoveIPC=true
SystemCallFilter=~@clock
SystemCallFilter=~@aio
SystemCallFilter=~@chown
SystemCallFilter=~@cpu-emulation
SystemCallFilter=~@debug
SystemCallFilter=~@keyring
SystemCallFilter=~@memlock
SystemCallFilter=~@module
SystemCallFilter=~@mount
SystemCallFilter=~@obsolete
SystemCallFilter=~@privileged
SystemCallFilter=~@raw-io
SystemCallFilter=~@reboot
SystemCallFilter=~@setuid
SystemCallFilter=~@swap
SystemCallErrorNumber=EPERM
[Install]
WantedBy = multi-user.target

View File

@@ -7,7 +7,7 @@
%endif
Name: jellyfin
Version: 10.8.3
Version: 10.8.8
Release: 1%{?dist}
Summary: The Free Software Media System
License: GPLv2
@@ -68,7 +68,7 @@ export DOTNET_CLI_TELEMETRY_OPTOUT=1
export PATH=$PATH:/usr/local/bin
# cannot use --output due to https://github.com/dotnet/sdk/issues/22220
dotnet publish --configuration Release --self-contained --runtime %{dotnet_runtime} \
"-p:DebugSymbols=false;DebugType=none" Jellyfin.Server
-p:DebugSymbols=false -p:DebugType=none Jellyfin.Server
%install
@@ -176,6 +176,16 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
* Tue Nov 29 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.8; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.8
* Mon Oct 31 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.7; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.7
* Fri Oct 28 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.6; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.6
* Sat Sep 24 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.5
* Sat Aug 13 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.4; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.4
* Mon Aug 01 2022 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.8.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.8.3
* Mon Aug 01 2022 Jellyfin Packaging Team <packaging@jellyfin.org>

View File

@@ -13,7 +13,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Extensions</PackageId>
<VersionPrefix>10.8.3</VersionPrefix>
<VersionPrefix>10.8.8</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -11,7 +11,7 @@ namespace Jellyfin.MediaEncoding.Keyframes.FfProbe;
/// </summary>
public static class FfProbeKeyframeExtractor
{
private const string DefaultArguments = "-v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"";
private const string DefaultArguments = "-fflags +genpts -v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"";
/// <summary>
/// Extracts the keyframes using the ffprobe executable at the specified path.
@@ -38,9 +38,28 @@ public static class FfProbeKeyframeExtractor
EnableRaisingEvents = true
};
process.Start();
try
{
process.Start();
return ParseStream(process.StandardOutput);
return ParseStream(process.StandardOutput);
}
catch (Exception)
{
try
{
if (!process.HasExited)
{
process.Kill();
}
}
catch
{
// We do not care if this fails
}
throw;
}
}
internal static KeyframeData ParseStream(StreamReader reader)
@@ -62,12 +81,17 @@ public static class FfProbeKeyframeExtractor
var rest = line[(firstComma + 1)..];
if (lineType.Equals("packet", StringComparison.OrdinalIgnoreCase))
{
if (rest.EndsWith(",K_"))
// Split time and flags from the packet line. Example line: packet,7169.079000,K_
var secondComma = rest.IndexOf(',');
var ptsTime = rest[..secondComma];
var flags = rest[(secondComma + 1)..];
if (flags.StartsWith("K_"))
{
// Trim the flags from the packet line. Example line: packet,7169.079000,K_
var keyframe = double.Parse(rest[..^3], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture);
// Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
if (double.TryParse(ptsTime, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var keyframe))
{
// Have to manually convert to ticks to avoid rounding errors as TimeSpan is only precise down to 1 ms when converting double.
keyframes.Add(Convert.ToInt64(keyframe * TimeSpan.TicksPerSecond));
}
}
}
else if (lineType.Equals("stream", StringComparison.OrdinalIgnoreCase))

View File

@@ -21,7 +21,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -15,9 +15,9 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -22,7 +22,7 @@
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -127,14 +127,14 @@ namespace Jellyfin.Model.Tests.Entities
[InlineData(2560, 1080, true, "1080i")]
[InlineData(4096, 3072, false, "4K")]
[InlineData(8192, 6144, false, "8K")]
[InlineData(512, 384, false, "480p")]
[InlineData(512, 384, false, "384p")]
[InlineData(576, 336, false, "360p")]
[InlineData(576, 336, true, "360i")]
[InlineData(624, 352, false, "360p")]
[InlineData(640, 352, false, "360p")]
[InlineData(640, 480, false, "480p")]
[InlineData(704, 396, false, "480p")]
[InlineData(720, 404, false, "480p")]
[InlineData(704, 396, false, "404p")]
[InlineData(720, 404, false, "404p")]
[InlineData(720, 480, false, "480p")]
[InlineData(720, 576, false, "576p")]
[InlineData(768, 576, false, "576p")]

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -13,7 +13,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -21,7 +21,7 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

View File

@@ -9,9 +9,9 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -10,9 +10,9 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>

View File

@@ -13,7 +13,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">