mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-11-27 16:55:00 -05:00
Backport pull request #15263 from jellyfin/release-10.11.z
Resolve symlinks for static media source infos Original-merge: 3b2d64995aab63ebaa6832c059a3cc0bdebe90dc Merged-by: crobibero <cody@robibe.ro> Backported-by: Bond_009 <bond.009@outlook.com>
This commit is contained in:
parent
06fb300cff
commit
5ea3910af9
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Security;
|
using System.Security;
|
||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@ -260,7 +261,7 @@ namespace Emby.Server.Implementations.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var targetFileInfo = (FileInfo?)fileInfo.ResolveLinkTarget(returnFinalTarget: true);
|
var targetFileInfo = FileSystemHelper.ResolveLinkTarget(fileInfo, returnFinalTarget: true);
|
||||||
if (targetFileInfo is not null)
|
if (targetFileInfo is not null)
|
||||||
{
|
{
|
||||||
result.Exists = targetFileInfo.Exists;
|
result.Exists = targetFileInfo.Exists;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule
|
|||||||
|
|
||||||
private static string GetFileContent(FileInfo dirIgnoreFile)
|
private static string GetFileContent(FileInfo dirIgnoreFile)
|
||||||
{
|
{
|
||||||
dirIgnoreFile = (FileInfo?)dirIgnoreFile.ResolveLinkTarget(returnFinalTarget: true) ?? dirIgnoreFile;
|
dirIgnoreFile = FileSystemHelper.ResolveLinkTarget(dirIgnoreFile, returnFinalTarget: true) ?? dirIgnoreFile;
|
||||||
if (!dirIgnoreFile.Exists)
|
if (!dirIgnoreFile.Exists)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|||||||
@ -254,10 +254,10 @@ public class TrickplayManager : ITrickplayManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We support video backdrops, but we should not generate trickplay images for them
|
// We support video backdrops, but we should not generate trickplay images for them
|
||||||
var parentDirectory = Directory.GetParent(mediaPath);
|
var parentDirectory = Directory.GetParent(video.Path);
|
||||||
if (parentDirectory is not null && string.Equals(parentDirectory.Name, "backdrops", StringComparison.OrdinalIgnoreCase))
|
if (parentDirectory is not null && string.Equals(parentDirectory.Name, "backdrops", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Ignoring backdrop media found at {Path} for item {ItemID}", mediaPath, video.Id);
|
_logger.LogDebug("Ignoring backdrop media found at {Path} for item {ItemID}", video.Path, video.Id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ using MediaBrowser.Controller.Configuration;
|
|||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaSegments;
|
using MediaBrowser.Controller.MediaSegments;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
@ -1127,6 +1128,15 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
var protocol = item.PathProtocol;
|
var protocol = item.PathProtocol;
|
||||||
|
|
||||||
|
// Resolve the item path so everywhere we use the media source it will always point to
|
||||||
|
// the correct path even if symlinks are in use. Calling ResolveLinkTarget on a non-link
|
||||||
|
// path will return null, so it's safe to check for all paths.
|
||||||
|
var itemPath = item.Path;
|
||||||
|
if (protocol is MediaProtocol.File && FileSystemHelper.ResolveLinkTarget(itemPath, returnFinalTarget: true) is { Exists: true } linkInfo)
|
||||||
|
{
|
||||||
|
itemPath = linkInfo.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
var info = new MediaSourceInfo
|
var info = new MediaSourceInfo
|
||||||
{
|
{
|
||||||
Id = item.Id.ToString("N", CultureInfo.InvariantCulture),
|
Id = item.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||||
@ -1134,7 +1144,7 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
MediaStreams = MediaSourceManager.GetMediaStreams(item.Id),
|
MediaStreams = MediaSourceManager.GetMediaStreams(item.Id),
|
||||||
MediaAttachments = MediaSourceManager.GetMediaAttachments(item.Id),
|
MediaAttachments = MediaSourceManager.GetMediaAttachments(item.Id),
|
||||||
Name = GetMediaSourceName(item),
|
Name = GetMediaSourceName(item),
|
||||||
Path = enablePathSubstitution ? GetMappedPath(item, item.Path, protocol) : item.Path,
|
Path = enablePathSubstitution ? GetMappedPath(item, itemPath, protocol) : itemPath,
|
||||||
RunTimeTicks = item.RunTimeTicks,
|
RunTimeTicks = item.RunTimeTicks,
|
||||||
Container = item.Container,
|
Container = item.Container,
|
||||||
Size = item.Size,
|
Size = item.Size,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
@ -61,4 +62,77 @@ public static class FileSystemHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target of the specified file link.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This helper exists because of this upstream runtime issue; https://github.com/dotnet/runtime/issues/92128.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="linkPath">The path of the file link.</param>
|
||||||
|
/// <param name="returnFinalTarget">true to follow links to the final target; false to return the immediate next link.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="FileInfo"/> if the <paramref name="linkPath"/> is a link, regardless of if the target exists; otherwise, <c>null</c>.
|
||||||
|
/// </returns>
|
||||||
|
public static FileInfo? ResolveLinkTarget(string linkPath, bool returnFinalTarget = false)
|
||||||
|
{
|
||||||
|
// Check if the file exists so the native resolve handler won't throw at us.
|
||||||
|
if (!File.Exists(linkPath))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!returnFinalTarget)
|
||||||
|
{
|
||||||
|
return File.ResolveLinkTarget(linkPath, returnFinalTarget: false) as FileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.ResolveLinkTarget(linkPath, returnFinalTarget: false) is not FileInfo targetInfo)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentPath = targetInfo.FullName;
|
||||||
|
var visited = new HashSet<string>(StringComparer.Ordinal) { linkPath, currentPath };
|
||||||
|
while (File.ResolveLinkTarget(currentPath, returnFinalTarget: false) is FileInfo linkInfo)
|
||||||
|
{
|
||||||
|
var targetPath = linkInfo.FullName;
|
||||||
|
|
||||||
|
// If an infinite loop is detected, return the file info for the
|
||||||
|
// first link in the loop we encountered.
|
||||||
|
if (!visited.Add(targetPath))
|
||||||
|
{
|
||||||
|
return new FileInfo(targetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
targetInfo = linkInfo;
|
||||||
|
currentPath = targetPath;
|
||||||
|
|
||||||
|
// Exit if the target doesn't exist, so the native resolve handler won't throw at us.
|
||||||
|
if (!targetInfo.Exists)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target of the specified file link.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This helper exists because of this upstream runtime issue; https://github.com/dotnet/runtime/issues/92128.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="fileInfo">The file info of the file link.</param>
|
||||||
|
/// <param name="returnFinalTarget">true to follow links to the final target; false to return the immediate next link.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="FileInfo"/> if the <paramref name="fileInfo"/> is a link, regardless of if the target exists; otherwise, <c>null</c>.
|
||||||
|
/// </returns>
|
||||||
|
public static FileInfo? ResolveLinkTarget(FileInfo fileInfo, bool returnFinalTarget = false)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(fileInfo);
|
||||||
|
|
||||||
|
return ResolveLinkTarget(fileInfo.FullName, returnFinalTarget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user