mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-12 12:03:02 +03:00
Compare commits
19 Commits
v10.8.0-al
...
v10.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b73e74ce5 | ||
|
|
8bb03e8f91 | ||
|
|
3e742e99a5 | ||
|
|
ad3a96267e | ||
|
|
8b42ef451c | ||
|
|
4ce16489a4 | ||
|
|
809651ceaf | ||
|
|
6547ae46ce | ||
|
|
cbf6ef4dbd | ||
|
|
e4ce72e7bb | ||
|
|
3b758c3a66 | ||
|
|
dadd42e574 | ||
|
|
349b789492 | ||
|
|
0ee0aa8941 | ||
|
|
94dbdd9f98 | ||
|
|
9875f30836 | ||
|
|
a717a531bc | ||
|
|
d04e255a79 | ||
|
|
2fd902f1b2 |
@@ -18,7 +18,21 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
"**/small.jpg",
|
||||
"**/albumart.jpg",
|
||||
"**/*sample*",
|
||||
|
||||
// We have neither non-greedy matching or character group repetitions, working around that here.
|
||||
// https://github.com/dazinator/DotNet.Glob#patterns
|
||||
// .*/sample\..{1,5}
|
||||
"**/sample.?",
|
||||
"**/sample.??",
|
||||
"**/sample.???", // Matches sample.mkv
|
||||
"**/sample.????", // Matches sample.webm
|
||||
"**/sample.?????",
|
||||
"**/*.sample.?",
|
||||
"**/*.sample.??",
|
||||
"**/*.sample.???",
|
||||
"**/*.sample.????",
|
||||
"**/*.sample.?????",
|
||||
"**/sample/*",
|
||||
|
||||
// Directories
|
||||
"**/metadata/**",
|
||||
@@ -64,10 +78,13 @@ namespace Emby.Server.Implementations.Library
|
||||
"**/.grab/**",
|
||||
"**/.grab",
|
||||
|
||||
// Unix hidden files and directories
|
||||
"**/.*/**",
|
||||
// Unix hidden files
|
||||
"**/.*",
|
||||
|
||||
// Mac - if you ever remove the above.
|
||||
// "**/._*",
|
||||
// "**/.DS_Store",
|
||||
|
||||
// thumbs.db
|
||||
"**/thumbs.db",
|
||||
|
||||
|
||||
@@ -1876,7 +1876,8 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
|
||||
var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray();
|
||||
if (outdated.Length == 0)
|
||||
// Skip image processing if current or live tv source
|
||||
if (outdated.Length == 0 || item.SourceType != SourceType.Library)
|
||||
{
|
||||
RegisterItem(item);
|
||||
return;
|
||||
|
||||
@@ -152,7 +152,12 @@ namespace Emby.Server.Implementations.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] octet = IPAddress.Parse(endpoint).GetAddressBytes();
|
||||
if (!IPAddress.TryParse(endpoint, out var ipAddress))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] octet = ipAddress.GetAddressBytes();
|
||||
|
||||
if ((octet[0] == 10) ||
|
||||
(octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918
|
||||
@@ -268,6 +273,12 @@ namespace Emby.Server.Implementations.Networking
|
||||
string excludeAddress = "[" + addressString + "]";
|
||||
var subnets = LocalSubnetsFn();
|
||||
|
||||
// Include any address if LAN subnets aren't specified
|
||||
if (subnets.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exclude any addresses if they appear in the LAN list in [ ]
|
||||
if (Array.IndexOf(subnets, excludeAddress) != -1)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data;
|
||||
using Jellyfin.Data.Entities;
|
||||
@@ -133,6 +134,18 @@ namespace Jellyfin.Server.Implementations
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
foreach (var entry in ChangeTracker.Entries())
|
||||
{
|
||||
entry.State = EntityState.Detached;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
@@ -102,7 +102,16 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Guid> UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id);
|
||||
public IEnumerable<Guid> UsersIds
|
||||
{
|
||||
get
|
||||
{
|
||||
using var dbContext = _dbProvider.CreateContext();
|
||||
return dbContext.Users
|
||||
.Select(user => user.Id)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public User? GetUserById(Guid id)
|
||||
@@ -152,12 +161,12 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
throw new ArgumentException("Invalid username", nameof(newName));
|
||||
}
|
||||
|
||||
if (user.Username.Equals(newName, StringComparison.OrdinalIgnoreCase))
|
||||
if (user.Username.Equals(newName, StringComparison.Ordinal))
|
||||
{
|
||||
throw new ArgumentException("The new and old names must be different.");
|
||||
}
|
||||
|
||||
if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)))
|
||||
if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.Ordinal)))
|
||||
{
|
||||
throw new ArgumentException(string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
@@ -637,7 +646,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
/// <inheritdoc/>
|
||||
public void UpdateConfiguration(Guid userId, UserConfiguration config)
|
||||
{
|
||||
var dbContext = _dbProvider.CreateContext();
|
||||
using var dbContext = _dbProvider.CreateContext();
|
||||
var user = dbContext.Users
|
||||
.Include(u => u.Permissions)
|
||||
.Include(u => u.Preferences)
|
||||
@@ -670,7 +679,7 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
/// <inheritdoc/>
|
||||
public void UpdatePolicy(Guid userId, UserPolicy policy)
|
||||
{
|
||||
var dbContext = _dbProvider.CreateContext();
|
||||
using var dbContext = _dbProvider.CreateContext();
|
||||
var user = dbContext.Users
|
||||
.Include(u => u.Permissions)
|
||||
.Include(u => u.Preferences)
|
||||
@@ -749,8 +758,8 @@ namespace Jellyfin.Server.Implementations.Users
|
||||
{
|
||||
// This is some regex that matches only on unicode "word" characters, as well as -, _ and @
|
||||
// In theory this will cut out most if not all 'control' characters which should help minimize any weirdness
|
||||
// Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), and periods (.)
|
||||
return Regex.IsMatch(name, @"^[\w\-'._@]*$");
|
||||
// Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), periods (.) and spaces ( )
|
||||
return Regex.IsMatch(name, @"^[\w\ \-'._@]*$");
|
||||
}
|
||||
|
||||
private IAuthenticationProvider GetAuthenticationProvider(User user)
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace Jellyfin.Server.Migrations
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to perform migration on a new install.
|
||||
/// </summary>
|
||||
public bool PerformOnNewInstall { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Execute the migration routine.
|
||||
/// </summary>
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations
|
||||
typeof(Routines.MigrateActivityLogDb),
|
||||
typeof(Routines.RemoveDuplicateExtras),
|
||||
typeof(Routines.AddDefaultPluginRepository),
|
||||
typeof(Routines.MigrateUserDb)
|
||||
typeof(Routines.MigrateUserDb),
|
||||
typeof(Routines.ReaddDefaultPluginRepository)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -43,9 +44,8 @@ namespace Jellyfin.Server.Migrations
|
||||
// If startup wizard is not finished, this is a fresh install.
|
||||
// Don't run any migrations, just mark all of them as applied.
|
||||
logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
|
||||
migrationOptions.Applied.AddRange(migrations.Select(m => (m.Id, m.Name)));
|
||||
migrationOptions.Applied.AddRange(migrations.Where(m => !m.PerformOnNewInstall).Select(m => (m.Id, m.Name)));
|
||||
host.ServerConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
||||
|
||||
@@ -32,6 +32,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "AddDefaultPluginRepository";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "CreateLoggingConfigHeirarchy";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "DisableTranscodingThrottling";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -41,6 +41,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "MigrateActivityLogDatabase";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -54,6 +54,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "MigrateUserDatabase";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Model.Updates;
|
||||
|
||||
namespace Jellyfin.Server.Migrations.Routines
|
||||
{
|
||||
/// <summary>
|
||||
/// Migration to initialize system configuration with the default plugin repository.
|
||||
/// </summary>
|
||||
public class ReaddDefaultPluginRepository : IMigrationRoutine
|
||||
{
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
|
||||
private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo
|
||||
{
|
||||
Name = "Jellyfin Stable",
|
||||
Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReaddDefaultPluginRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||
public ReaddDefaultPluginRepository(IServerConfigurationManager serverConfigurationManager)
|
||||
{
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Guid Id => Guid.Parse("5F86E7F6-D966-4C77-849D-7A7B40B68C4E");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "ReaddDefaultPluginRepository";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
// Only add if repository list is empty
|
||||
if (_serverConfigurationManager.Configuration.PluginRepositories.Count == 0)
|
||||
{
|
||||
_serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo);
|
||||
_serverConfigurationManager.SaveConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
||||
/// <inheritdoc/>
|
||||
public string Name => "RemoveDuplicateExtras";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool PerformOnNewInstall => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Perform()
|
||||
{
|
||||
|
||||
@@ -456,11 +456,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
if (!IsCopyCodec(outputVideoCodec))
|
||||
{
|
||||
if (state.IsVideoRequest
|
||||
&& IsVaapiSupported(state)
|
||||
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (isVaapiDecoder)
|
||||
@@ -495,13 +496,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
else
|
||||
{
|
||||
arg.Append("-hwaccel qsv -init_hw_device qsv=hw ");
|
||||
arg.Append("-hwaccel qsv ");
|
||||
}
|
||||
}
|
||||
|
||||
if (isWindows)
|
||||
{
|
||||
arg.Append("-hwaccel qsv -init_hw_device qsv=hw ");
|
||||
arg.Append("-hwaccel qsv ");
|
||||
}
|
||||
}
|
||||
// While using SW decoder
|
||||
@@ -511,6 +512,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.IsVideoRequest
|
||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
arg.Append("-hwaccel videotoolbox ");
|
||||
}
|
||||
}
|
||||
|
||||
arg.Append("-i ")
|
||||
@@ -1606,25 +1613,41 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
else
|
||||
{
|
||||
index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
|
||||
index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Substring(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
|
||||
index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Substring(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
|
||||
index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Substring(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Substring(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Substring(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1685,7 +1708,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
|
||||
else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1
|
||||
else if (_mediaEncoder.SupportsHwaccel("vaapi") && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1
|
||||
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
/*
|
||||
@@ -1790,6 +1813,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var outputWidth = width.Value;
|
||||
var outputHeight = height.Value;
|
||||
var qsv_or_vaapi = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase);
|
||||
var isDeintEnabled = state.DeInterlace("h264", true)
|
||||
|| state.DeInterlace("avc", true)
|
||||
|| state.DeInterlace("h265", true)
|
||||
|| state.DeInterlace("hevc", true);
|
||||
|
||||
if (!videoWidth.HasValue
|
||||
|| outputWidth != videoWidth.Value
|
||||
@@ -1805,7 +1832,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi",
|
||||
outputWidth,
|
||||
outputHeight,
|
||||
(qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty));
|
||||
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1814,7 +1841,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0}=format=nv12{1}",
|
||||
qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi",
|
||||
(qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty));
|
||||
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
|
||||
}
|
||||
}
|
||||
else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1
|
||||
@@ -2026,7 +2053,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/
|
||||
|
||||
var request = state.BaseRequest;
|
||||
|
||||
var videoStream = state.VideoStream;
|
||||
var filters = new List<string>();
|
||||
|
||||
@@ -2035,23 +2061,31 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var inputHeight = videoStream?.Height;
|
||||
var threeDFormat = state.MediaSource.Video3DFormat;
|
||||
|
||||
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
|
||||
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||
|
||||
// When the input may or may not be hardware VAAPI decodable
|
||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (isVaapiH264Encoder)
|
||||
{
|
||||
filters.Add("format=nv12|vaapi");
|
||||
filters.Add("hwupload");
|
||||
}
|
||||
|
||||
// When the input may or may not be hardware QSV decodable
|
||||
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
// When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context
|
||||
else if (isLinux && hasGraphicalSubs && isQsvH264Encoder)
|
||||
{
|
||||
filters.Add("format=nv12|qsv");
|
||||
filters.Add("hwupload=extra_hw_frames=64");
|
||||
}
|
||||
|
||||
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
|
||||
else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1
|
||||
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
else if (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder)
|
||||
{
|
||||
var codec = videoStream.Codec.ToLowerInvariant();
|
||||
var isColorDepth10 = IsColorDepth10(state);
|
||||
@@ -2079,16 +2113,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
// Add hardware deinterlace filter before scaling filter
|
||||
if (state.DeInterlace("h264", true))
|
||||
if (state.DeInterlace("h264", true) || state.DeInterlace("avc", true))
|
||||
{
|
||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (isVaapiH264Encoder)
|
||||
{
|
||||
filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi"));
|
||||
}
|
||||
}
|
||||
|
||||
// Add software deinterlace filter before scaling filter
|
||||
if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
|
||||
if (state.DeInterlace("h264", true)
|
||||
|| state.DeInterlace("avc", true)
|
||||
|| state.DeInterlace("h265", true)
|
||||
|| state.DeInterlace("hevc", true))
|
||||
{
|
||||
var deintParam = string.Empty;
|
||||
var inputFramerate = videoStream?.RealFrameRate;
|
||||
@@ -2105,9 +2142,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (!string.IsNullOrEmpty(deintParam))
|
||||
{
|
||||
if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
||||
&& videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder)
|
||||
{
|
||||
filters.Add(deintParam);
|
||||
}
|
||||
@@ -2117,12 +2152,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr
|
||||
filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
|
||||
|
||||
// Add parameters to use VAAPI with burn-in text subttiles (GH issue #642)
|
||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
|
||||
if (isVaapiH264Encoder)
|
||||
{
|
||||
if (state.SubtitleStream != null
|
||||
&& state.SubtitleStream.IsTextSubtitleStream
|
||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
||||
if (hasTextSubs)
|
||||
{
|
||||
// Test passed on Intel and AMD gfx
|
||||
filters.Add("hwmap=mode=read+write");
|
||||
@@ -2132,9 +2165,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
var output = string.Empty;
|
||||
|
||||
if (state.SubtitleStream != null
|
||||
&& state.SubtitleStream.IsTextSubtitleStream
|
||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
||||
if (hasTextSubs)
|
||||
{
|
||||
var subParam = GetTextSubtitleParam(state);
|
||||
|
||||
@@ -2142,7 +2173,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
// Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API
|
||||
// Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI
|
||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (isVaapiH264Encoder)
|
||||
{
|
||||
filters.Add("hwmap");
|
||||
}
|
||||
|
||||
@@ -172,7 +172,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
inputFiles = new[] { mediaSource.Path };
|
||||
}
|
||||
|
||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||
var protocol = mediaSource.Protocol;
|
||||
if (subtitleStream.IsExternal)
|
||||
{
|
||||
protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path);
|
||||
}
|
||||
|
||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -426,7 +432,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
// 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"
|
||||
if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && (encodingParam == "UTF-16BE" || encodingParam == "UTF-16LE"))
|
||||
if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) &&
|
||||
(encodingParam.Equals("UTF-16BE", StringComparison.OrdinalIgnoreCase) ||
|
||||
encodingParam.Equals("UTF-16LE", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
encodingParam = "";
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma warning disable CA1819 // Properties should not return arrays
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -9,21 +10,27 @@ namespace MediaBrowser.Model.Notifications
|
||||
public NotificationOption(string type)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
DisabledServices = Array.Empty<string>();
|
||||
DisabledMonitorUsers = Array.Empty<string>();
|
||||
SendToUsers = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string Type { get; set; }
|
||||
public NotificationOption()
|
||||
{
|
||||
DisabledServices = Array.Empty<string>();
|
||||
DisabledMonitorUsers = Array.Empty<string>();
|
||||
SendToUsers = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Ids to not monitor (it's opt out).
|
||||
/// Gets or sets user Ids to not monitor (it's opt out).
|
||||
/// </summary>
|
||||
public string[] DisabledMonitorUsers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Ids to send to (if SendToUserMode == Custom)
|
||||
/// Gets or sets user Ids to send to (if SendToUserMode == Custom).
|
||||
/// </summary>
|
||||
public string[] SendToUsers { get; set; }
|
||||
|
||||
|
||||
@@ -28,29 +28,31 @@
|
||||
pluginId: "a629c0da-fac5-4c7e-931a-7174223f14c8"
|
||||
};
|
||||
|
||||
$('.configPage').on('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
$('#enable').checked = config.Enable;
|
||||
$('#replaceAlbumName').checked = config.ReplaceAlbumName;
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
$('.configForm').on('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var form = this;
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
config.Enable = $('#enable', form).checked;
|
||||
config.ReplaceAlbumName = $('#replaceAlbumName', form).checked;
|
||||
|
||||
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
document.querySelector('.configPage')
|
||||
.addEventListener('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
document.querySelector('#enable').checked = config.Enable;
|
||||
document.querySelector('#replaceAlbumName').checked = config.ReplaceAlbumName;
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
document.querySelector('.configForm')
|
||||
.addEventListener('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
config.Enable = document.querySelector('#enable').checked;
|
||||
config.ReplaceAlbumName = document.querySelector('#replaceAlbumName').checked;
|
||||
|
||||
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
|
||||
public override string Description => "Get artist and album metadata or images from AudioDB.";
|
||||
|
||||
// TODO remove when plugin removed from server.
|
||||
public override string ConfigurationFileName => "Jellyfin.Plugin.AudioDb.xml";
|
||||
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
|
||||
@@ -36,33 +36,47 @@
|
||||
uniquePluginId: "8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a"
|
||||
};
|
||||
|
||||
$('.musicBrainzConfigPage').on('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||
$('#server').val(config.Server).change();
|
||||
$('#rateLimit').val(config.RateLimit).change();
|
||||
$('#enable').checked = config.Enable;
|
||||
$('#replaceArtistName').checked = config.ReplaceArtistName;
|
||||
document.querySelector('.musicBrainzConfigPage')
|
||||
.addEventListener('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||
var server = document.querySelector('#server');
|
||||
server.value = config.Server;
|
||||
server.dispatchEvent(new Event('change', {
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
var rateLimit = document.querySelector('#rateLimit');
|
||||
rateLimit.value = config.RateLimit;
|
||||
rateLimit.dispatchEvent(new Event('change', {
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
document.querySelector('#enable').checked = config.Enable;
|
||||
document.querySelector('#replaceArtistName').checked = config.ReplaceArtistName;
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('.musicBrainzConfigForm').on('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var form = this;
|
||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||
config.Server = $('#server', form).val();
|
||||
config.RateLimit = $('#rateLimit', form).val();
|
||||
config.Enable = $('#enable', form).checked;
|
||||
config.ReplaceArtistName = $('#replaceArtistName', form).checked;
|
||||
|
||||
ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
|
||||
document.querySelector('.musicBrainzConfigForm')
|
||||
.addEventListener('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||
config.Server = document.querySelector('#server').value;
|
||||
config.RateLimit = document.querySelector('#rateLimit').value;
|
||||
config.Enable = document.querySelector('#enable').checked;
|
||||
config.ReplaceArtistName = document.querySelector('#replaceArtistName').checked;
|
||||
|
||||
ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace MediaBrowser.Providers.Plugins.MusicBrainz
|
||||
|
||||
public const long DefaultRateLimit = 2000u;
|
||||
|
||||
// TODO remove when plugin removed from server.
|
||||
public override string ConfigurationFileName => "Jellyfin.Plugin.MusicBrainz.xml";
|
||||
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
|
||||
@@ -24,25 +24,28 @@
|
||||
pluginId: "a628c0da-fac5-4c7e-9d1a-7134223f14c8"
|
||||
};
|
||||
|
||||
$('.configPage').on('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
$('#castAndCrew').checked = config.CastAndCrew;
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
$('.configForm').on('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var form = this;
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
config.CastAndCrew = $('#castAndCrew', form).checked;
|
||||
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
document.querySelector('.configPage')
|
||||
.addEventListener('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
document.querySelector('#castAndCrew').checked = config.CastAndCrew;
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
document.querySelector('.configForm')
|
||||
.addEventListener('submit', function (e) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||
config.CastAndCrew = document.querySelector('#castAndCrew').checked;
|
||||
ApiClient.updatePluginConfiguration(PluginConfig.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb
|
||||
|
||||
public override string Description => "Get metadata for movies and other video content from OMDb.";
|
||||
|
||||
// TODO remove when plugin removed from server.
|
||||
public override string ConfigurationFileName => "Jellyfin.Plugin.Omdb.xml";
|
||||
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
|
||||
|
||||
public override string Description => "Get metadata for movies and other video content from TheTVDB.";
|
||||
|
||||
// TODO remove when plugin removed from server.
|
||||
public override string ConfigurationFileName => "Jellyfin.Plugin.TheTvdb.xml";
|
||||
|
||||
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||
: base(applicationPaths, xmlSerializer)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("10.6.0")]
|
||||
[assembly: AssemblyFileVersion("10.6.0")]
|
||||
[assembly: AssemblyVersion("10.6.1")]
|
||||
[assembly: AssemblyFileVersion("10.6.1")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin"
|
||||
version: "10.6.0"
|
||||
version: "10.6.1"
|
||||
packages:
|
||||
- debian.amd64
|
||||
- debian.arm64
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
jellyfin-server (10.6.1-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.6.1
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 18:59:03 -0400
|
||||
|
||||
jellyfin-server (10.6.0-2) unstable; urgency=medium
|
||||
|
||||
* Fix upgrade bug
|
||||
|
||||
-- Joshua Boniface <joshua@boniface.me> Sun, 19 Jul 22:47:27 -0400
|
||||
|
||||
jellyfin-server (10.6.0-1) unstable; urgency=medium
|
||||
|
||||
* Forthcoming stable release
|
||||
|
||||
4
debian/conf/jellyfin
vendored
4
debian/conf/jellyfin
vendored
@@ -31,7 +31,7 @@ JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg"
|
||||
#JELLYFIN_SERVICE_OPT="--service"
|
||||
|
||||
# [OPTIONAL] run Jellyfin without the web app
|
||||
#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp"
|
||||
#JELLYFIN_NOWEBAPP_OPT="--nowebclient"
|
||||
|
||||
#
|
||||
# SysV init/Upstart options
|
||||
@@ -40,4 +40,4 @@ JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg"
|
||||
# Application username
|
||||
JELLYFIN_USER="jellyfin"
|
||||
# Full application command
|
||||
JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT"
|
||||
JELLYFIN_ARGS="$JELLYFIN_WEB_OPT $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLYFIN_NOWEBAPP_OPT"
|
||||
|
||||
5
debian/control
vendored
5
debian/control
vendored
@@ -15,9 +15,8 @@ Vcs-Git: https://github.org/jellyfin/jellyfin.git
|
||||
Vcs-Browser: https://github.org/jellyfin/jellyfin
|
||||
|
||||
Package: jellyfin-server
|
||||
Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
||||
Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
||||
Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
||||
Replaces: jellyfin (<<10.6.0)
|
||||
Breaks: jellyfin (<<10.6.0)
|
||||
Architecture: any
|
||||
Depends: at,
|
||||
libsqlite3-0,
|
||||
|
||||
2
debian/metapackage/jellyfin
vendored
2
debian/metapackage/jellyfin
vendored
@@ -5,7 +5,7 @@ Homepage: https://jellyfin.org
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
Package: jellyfin
|
||||
Version: 10.6.0
|
||||
Version: 10.6.1
|
||||
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
Depends: jellyfin-server, jellyfin-web
|
||||
Description: Provides the Jellyfin Free Software Media System
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%endif
|
||||
|
||||
Name: jellyfin
|
||||
Version: 10.6.0
|
||||
Version: 10.6.1
|
||||
Release: 1%{?dist}
|
||||
Summary: The Free Software Media System
|
||||
License: GPLv3
|
||||
@@ -139,6 +139,8 @@ fi
|
||||
%systemd_postun_with_restart jellyfin.service
|
||||
|
||||
%changelog
|
||||
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.6.1
|
||||
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Forthcoming stable release
|
||||
* Fri Oct 11 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
|
||||
@@ -9,17 +9,29 @@ namespace Jellyfin.Server.Implementations.Tests.Library
|
||||
[InlineData("/media/small.jpg", true)]
|
||||
[InlineData("/media/albumart.jpg", true)]
|
||||
[InlineData("/media/movie.sample.mp4", true)]
|
||||
[InlineData("/media/movie/sample.mp4", true)]
|
||||
[InlineData("/media/movie/sample/movie.mp4", true)]
|
||||
[InlineData("/foo/sample/bar/baz.mkv", false)]
|
||||
[InlineData("/media/movies/the sample/the sample.mkv", false)]
|
||||
[InlineData("/media/movies/sampler.mkv", false)]
|
||||
[InlineData("/media/movies/#Recycle/test.txt", true)]
|
||||
[InlineData("/media/movies/#recycle/", true)]
|
||||
[InlineData("/media/movies/#recycle", true)]
|
||||
[InlineData("thumbs.db", true)]
|
||||
[InlineData(@"C:\media\movies\movie.avi", false)]
|
||||
[InlineData("/media/.hiddendir/file.mp4", true)]
|
||||
[InlineData("/media/.hiddendir/file.mp4", false)]
|
||||
[InlineData("/media/dir/.hiddenfile.mp4", true)]
|
||||
[InlineData("/media/dir/._macjunk.mp4", true)]
|
||||
[InlineData("/volume1/video/Series/@eaDir", true)]
|
||||
[InlineData("/volume1/video/Series/@eaDir/file.txt", true)]
|
||||
[InlineData("/directory/@Recycle", true)]
|
||||
[InlineData("/directory/@Recycle/file.mp3", true)]
|
||||
[InlineData("/media/movies/.@__thumb", true)]
|
||||
[InlineData("/media/movies/.@__thumb/foo-bar-thumbnail.png", true)]
|
||||
[InlineData("/media/music/Foo B.A.R./epic.flac", false)]
|
||||
[InlineData("/media/music/Foo B.A.R", false)]
|
||||
// This test is pending an upstream fix: https://github.com/dazinator/DotNet.Glob/issues/78
|
||||
// [InlineData("/media/music/Foo B.A.R.", false)]
|
||||
public void PathIgnored(string path, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, IgnorePatterns.ShouldIgnore(path));
|
||||
|
||||
Reference in New Issue
Block a user