Compare commits

...

8 Commits

Author SHA1 Message Date
Tim Eisele a28d8fb0a1
Merge f1b1c7355c into 5612cb8178 2024-04-25 09:15:45 -04:00
renovate[bot] 5612cb8178
chore(deps): update ci dependencies (#11427)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-25 07:15:31 -06:00
renovate[bot] ccd06bc547
chore(deps): update dependency diacritics to v3.3.29 (#11429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-25 07:02:45 -06:00
Bond-009 d29b85a134
Fix multiple intro providers and remove unneeded ToLists (#11431) 2024-04-25 07:02:01 -06:00
Shadowghost f1b1c7355c Cleanup 2024-03-09 17:45:22 +01:00
Shadowghost a68dd94174 Simplyfy LocalAccessOrRequiresElevationHandler 2024-03-09 17:45:22 +01:00
Shadowghost c41d95b31b Enforce playback permission 2024-03-09 17:45:20 +01:00
Shadowghost a75c9d4547 Add playback auth permission 2024-03-09 17:44:55 +01:00
20 changed files with 58 additions and 50 deletions

View File

@ -20,7 +20,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- name: Setup .NET
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
with:

View File

@ -14,7 +14,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@ -39,7 +39,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@ -78,12 +78,12 @@ jobs:
- openapi-base
steps:
- name: Download openapi-head
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: openapi-head
path: openapi-head
- name: Download openapi-base
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: openapi-base
path: openapi-base
@ -152,7 +152,7 @@ jobs:
run: |-
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
- name: Download openapi-head
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: openapi-head
path: openapi-head

View File

@ -19,7 +19,7 @@ jobs:
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
with:

View File

@ -24,7 +24,7 @@ jobs:
reactions: '+1'
- name: Checkout the latest code
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@ -51,7 +51,7 @@ jobs:
reactions: eyes
- name: Checkout the latest code
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@ -128,7 +128,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: pull in script
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
repository: jellyfin/jellyfin-triage-script
- name: install python

View File

@ -10,7 +10,7 @@ jobs:
issues: write
steps:
- name: pull in script
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
repository: jellyfin/jellyfin-triage-script
- name: install python

View File

@ -33,7 +33,7 @@ jobs:
yq-version: v4.9.8
- name: Checkout Repository
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
ref: ${{ env.TAG_BRANCH }}
@ -66,7 +66,7 @@ jobs:
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
steps:
- name: Checkout Repository
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
ref: ${{ env.TAG_BRANCH }}

View File

@ -13,7 +13,7 @@
<PackageVersion Include="BlurHashSharp" Version="1.3.2" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Diacritics" Version="3.3.27" />
<PackageVersion Include="Diacritics" Version="3.3.29" />
<PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
<PackageVersion Include="DotNet.Glob" Version="3.1.3" />
<PackageVersion Include="EFCoreSecondLevelCacheInterceptor" Version="4.4.3" />

View File

@ -44,7 +44,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
using TMDbLib.Objects.Authentication;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
using Genre = MediaBrowser.Controller.Entities.Genre;
@ -1612,14 +1611,18 @@ namespace Emby.Server.Implementations.Library
/// <returns>IEnumerable{System.String}.</returns>
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
{
if (IntroProviders.Length == 0)
{
return [];
}
var tasks = IntroProviders
.Take(1)
.Select(i => GetIntros(i, item, user));
var items = await Task.WhenAll(tasks).ConfigureAwait(false);
return items
.SelectMany(i => i.ToArray())
.SelectMany(i => i)
.Select(ResolveIntro)
.Where(i => i is not null)!; // null values got filtered out
}

View File

@ -274,7 +274,7 @@ namespace Emby.Server.Implementations.Library
var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken));
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
return results.SelectMany(i => i.ToList());
return results.SelectMany(i => i);
}
private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(BaseItem item, IMediaSourceProvider provider, CancellationToken cancellationToken)

View File

@ -34,20 +34,9 @@ namespace Jellyfin.Api.Auth.LocalAccessOrRequiresElevationPolicy
var ip = _httpContextAccessor.HttpContext?.GetNormalizedRemoteIP();
// Loopback will be on LAN, so we can accept null.
if (ip is null || _networkManager.IsInLocalNetwork(ip))
if (ip is null || _networkManager.IsInLocalNetwork(ip) || context.User.IsInRole(UserRoles.Administrator))
{
context.Succeed(requirement);
return Task.CompletedTask;
}
if (context.User.IsInRole(UserRoles.Administrator))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;

View File

@ -4,10 +4,11 @@ using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Api;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Streaming;
using MediaBrowser.Model.Dlna;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -16,6 +17,7 @@ namespace Jellyfin.Api.Controllers;
/// <summary>
/// The audio controller.
/// </summary>
[Authorize(Policy = Policies.Playback)]
public class AudioController : BaseJellyfinApiController
{
private readonly AudioHelper _audioHelper;

View File

@ -15,6 +15,7 @@ using Jellyfin.Api.Models.StreamingDtos;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using Jellyfin.MediaEncoding.Hls.Playlist;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
@ -36,16 +37,14 @@ namespace Jellyfin.Api.Controllers;
/// <summary>
/// Dynamic hls controller.
/// </summary>
[Route("")]
[Authorize]
[Authorize(Policy = Policies.Playback)]
public class DynamicHlsController : BaseJellyfinApiController
{
private const string DefaultVodEncoderPreset = "veryfast";
private const string DefaultEventEncoderPreset = "superfast";
private const TranscodingJobType TranscodingJobType = MediaBrowser.Controller.MediaEncoding.TranscodingJobType.Hls;
private const TranscodingJobType DefaultTranscodingJobType = TranscodingJobType.Hls;
private readonly Version _minFFmpegFlacInMp4 = new Version(6, 0);
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IMediaSourceManager _mediaSourceManager;
@ -285,7 +284,7 @@ public class DynamicHlsController : BaseJellyfinApiController
_mediaEncoder,
_encodingHelper,
_transcodeManager,
TranscodingJobType,
DefaultTranscodingJobType,
cancellationToken)
.ConfigureAwait(false);
@ -306,7 +305,7 @@ public class DynamicHlsController : BaseJellyfinApiController
playlistPath,
GetCommandLineArguments(playlistPath, state, true, 0),
Request.HttpContext.User.GetUserId(),
TranscodingJobType,
DefaultTranscodingJobType,
cancellationTokenSource)
.ConfigureAwait(false);
job.IsLiveOutput = true;
@ -326,7 +325,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
}
job ??= _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
job ??= _transcodeManager.OnTranscodeBeginRequest(playlistPath, DefaultTranscodingJobType);
if (job is not null)
{
@ -508,7 +507,7 @@ public class DynamicHlsController : BaseJellyfinApiController
EnableTrickplay = enableTrickplay
};
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
return await _dynamicHlsHelper.GetMasterHlsPlaylist(DefaultTranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
}
/// <summary>
@ -674,7 +673,7 @@ public class DynamicHlsController : BaseJellyfinApiController
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming
};
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
return await _dynamicHlsHelper.GetMasterHlsPlaylist(DefaultTranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
}
/// <summary>
@ -1379,7 +1378,7 @@ public class DynamicHlsController : BaseJellyfinApiController
_mediaEncoder,
_encodingHelper,
_transcodeManager,
TranscodingJobType,
DefaultTranscodingJobType,
cancellationTokenSource.Token)
.ConfigureAwait(false);
@ -1417,7 +1416,7 @@ public class DynamicHlsController : BaseJellyfinApiController
_mediaEncoder,
_encodingHelper,
_transcodeManager,
TranscodingJobType,
DefaultTranscodingJobType,
cancellationToken)
.ConfigureAwait(false);
@ -1431,7 +1430,7 @@ public class DynamicHlsController : BaseJellyfinApiController
if (System.IO.File.Exists(segmentPath))
{
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, DefaultTranscodingJobType);
_logger.LogDebug("returning {0} [it exists, try 1]", segmentPath);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
}
@ -1441,7 +1440,7 @@ public class DynamicHlsController : BaseJellyfinApiController
var startTranscoding = false;
if (System.IO.File.Exists(segmentPath))
{
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, DefaultTranscodingJobType);
_logger.LogDebug("returning {0} [it exists, try 2]", segmentPath);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
}
@ -1492,7 +1491,7 @@ public class DynamicHlsController : BaseJellyfinApiController
playlistPath,
GetCommandLineArguments(playlistPath, state, false, segmentId),
Request.HttpContext.User.GetUserId(),
TranscodingJobType,
DefaultTranscodingJobType,
cancellationTokenSource).ConfigureAwait(false);
}
catch
@ -1505,7 +1504,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
else
{
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
job = _transcodeManager.OnTranscodeBeginRequest(playlistPath, DefaultTranscodingJobType);
if (job?.TranscodingThrottler is not null)
{
await job.TranscodingThrottler.UnpauseTranscoding().ConfigureAwait(false);
@ -1514,7 +1513,7 @@ public class DynamicHlsController : BaseJellyfinApiController
}
_logger.LogDebug("returning {0} [general case]", segmentPath);
job ??= _transcodeManager.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
job ??= _transcodeManager.OnTranscodeBeginRequest(playlistPath, DefaultTranscodingJobType);
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
}
@ -1970,7 +1969,7 @@ public class DynamicHlsController : BaseJellyfinApiController
private int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
{
var job = _transcodeManager.GetTranscodingJob(playlist, TranscodingJobType);
var job = _transcodeManager.GetTranscodingJob(playlist, DefaultTranscodingJobType);
if (job is null || job.HasExited)
{

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
@ -20,6 +21,7 @@ namespace Jellyfin.Api.Controllers;
/// The hls segment controller.
/// </summary>
[Route("")]
[Authorize(Policy = Policies.Playback)]
public class HlsSegmentController : BaseJellyfinApiController
{
private readonly IFileSystem _fileSystem;

View File

@ -1156,6 +1156,7 @@ public class LiveTvController : BaseJellyfinApiController
/// or a <see cref="NotFoundResult"/> if recording not found.
/// </returns>
[HttpGet("LiveRecordings/{recordingId}/stream")]
[Authorize(Policy = Policies.Playback)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesVideoFile]
@ -1183,6 +1184,7 @@ public class LiveTvController : BaseJellyfinApiController
/// or a <see cref="NotFoundResult"/> if stream not found.
/// </returns>
[HttpGet("LiveStreamFiles/{streamId}/stream.{container}")]
[Authorize(Policy = Policies.Playback)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesVideoFile]

View File

@ -8,6 +8,7 @@ using Jellyfin.Api.Attributes;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.ModelBinders;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Common.Api;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Extensions;
@ -28,6 +29,7 @@ namespace Jellyfin.Api.Controllers;
/// The universal audio controller.
/// </summary>
[Route("")]
[Authorize(Policy = Policies.Playback)]
public class UniversalAudioController : BaseJellyfinApiController
{
private readonly ILibraryManager _libraryManager;
@ -89,7 +91,6 @@ public class UniversalAudioController : BaseJellyfinApiController
/// <returns>A <see cref="Task"/> containing the audio file.</returns>
[HttpGet("Audio/{itemId}/universal")]
[HttpHead("Audio/{itemId}/universal", Name = "HeadUniversalAudioStream")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesResponseType(StatusCodes.Status404NotFound)]

View File

@ -10,6 +10,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@ -19,6 +20,7 @@ namespace Jellyfin.Api.Controllers;
/// Attachments controller.
/// </summary>
[Route("Videos")]
[Authorize]
public class VideoAttachmentsController : BaseJellyfinApiController
{
private readonly ILibraryManager _libraryManager;

View File

@ -310,6 +310,7 @@ public class VideosController : BaseJellyfinApiController
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
[HttpGet("{itemId}/stream")]
[HttpHead("{itemId}/stream", Name = "HeadVideoStream")]
[Authorize(Policy = Policies.Playback)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesVideoFile]
public async Task<ActionResult> GetVideoStream(
@ -548,6 +549,7 @@ public class VideosController : BaseJellyfinApiController
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
[HttpGet("{itemId}/stream.{container}")]
[HttpHead("{itemId}/stream.{container}", Name = "HeadVideoStreamByContainer")]
[Authorize(Policy = Policies.Playback)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesVideoFile]
public Task<ActionResult> GetVideoStreamByContainer(

View File

@ -77,6 +77,7 @@ namespace Jellyfin.Server.Extensions
options.AddPolicy(Policies.LiveTvAccess, new UserPermissionRequirement(PermissionKind.EnableLiveTvAccess));
options.AddPolicy(Policies.LiveTvManagement, new UserPermissionRequirement(PermissionKind.EnableLiveTvManagement));
options.AddPolicy(Policies.LocalAccessOrRequiresElevation, new LocalAccessOrRequiresElevationRequirement());
options.AddPolicy(Policies.Playback, new UserPermissionRequirement(PermissionKind.EnableMediaPlayback));
options.AddPolicy(Policies.SyncPlayHasAccess, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.HasAccess));
options.AddPolicy(Policies.SyncPlayCreateGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.CreateGroup));
options.AddPolicy(Policies.SyncPlayJoinGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.JoinGroup));

View File

@ -94,4 +94,9 @@ public static class Policies
/// Policy name for accessing lyric management.
/// </summary>
public const string LyricManagement = "LyricManagement";
/// <summary>
/// Policy name for playback.
/// </summary>
public const string Playback = "Playback";
}

View File

@ -286,7 +286,7 @@ namespace MediaBrowser.Providers.Manager
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
return results.SelectMany(i => i.ToList());
return results.SelectMany(i => i);
}
/// <summary>