Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4187c6f620 | |||
| e7dbb3afec | |||
| f994dd6211 | |||
| da254ee968 | |||
| 4ad3141875 | |||
| b5f0199a25 | |||
| 6bf88c049e | |||
| 40a33da2a5 | |||
| 3596fc0693 |
@@ -36,7 +36,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Naming</PackageId>
|
<PackageId>Jellyfin.Naming</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -113,8 +113,10 @@ namespace Emby.Naming.TV
|
|||||||
var numberString = match.Groups["seasonnumber"];
|
var numberString = match.Groups["seasonnumber"];
|
||||||
if (numberString.Success)
|
if (numberString.Success)
|
||||||
{
|
{
|
||||||
var seasonNumber = int.Parse(numberString.Value, CultureInfo.InvariantCulture);
|
if (int.TryParse(numberString.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var seasonNumber))
|
||||||
return (seasonNumber, true);
|
{
|
||||||
|
return (seasonNumber, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (null, false);
|
return (null, false);
|
||||||
|
|||||||
@@ -1625,8 +1625,11 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
|
|
||||||
var useLegacySegmentOption = _mediaEncoder.EncoderVersion < _minFFmpegHlsSegmentOptions;
|
var useLegacySegmentOption = _mediaEncoder.EncoderVersion < _minFFmpegHlsSegmentOptions;
|
||||||
|
|
||||||
// fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT
|
if (state.VideoStream is not null && state.IsOutputVideo)
|
||||||
hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont";
|
{
|
||||||
|
// fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT
|
||||||
|
hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont";
|
||||||
|
}
|
||||||
|
|
||||||
segmentFormat = "fmp4" + outputFmp4HeaderArg;
|
segmentFormat = "fmp4" + outputFmp4HeaderArg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Data</PackageId>
|
<PackageId>Jellyfin.Data</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -92,33 +93,38 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork)
|
public async Task<ForgotPasswordResult> StartForgotPasswordProcess(User? user, string enteredUsername, bool isInNetwork)
|
||||||
{
|
{
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
RandomNumberGenerator.Fill(bytes);
|
|
||||||
string pin = BitConverter.ToString(bytes);
|
|
||||||
|
|
||||||
DateTime expireTime = DateTime.UtcNow.AddMinutes(30);
|
DateTime expireTime = DateTime.UtcNow.AddMinutes(30);
|
||||||
string filePath = _passwordResetFileBase + user.Id + ".json";
|
var usernameHash = enteredUsername.ToUpperInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
|
||||||
SerializablePasswordReset spr = new SerializablePasswordReset
|
var pinFile = _passwordResetFileBase + usernameHash + ".json";
|
||||||
{
|
|
||||||
ExpirationDate = expireTime,
|
|
||||||
Pin = pin,
|
|
||||||
PinFile = filePath,
|
|
||||||
UserName = user.Username
|
|
||||||
};
|
|
||||||
|
|
||||||
FileStream fileStream = AsyncFile.Create(filePath);
|
if (user is not null && isInNetwork)
|
||||||
await using (fileStream.ConfigureAwait(false))
|
|
||||||
{
|
{
|
||||||
await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false);
|
byte[] bytes = new byte[4];
|
||||||
|
RandomNumberGenerator.Fill(bytes);
|
||||||
|
string pin = BitConverter.ToString(bytes);
|
||||||
|
|
||||||
|
SerializablePasswordReset spr = new SerializablePasswordReset
|
||||||
|
{
|
||||||
|
ExpirationDate = expireTime,
|
||||||
|
Pin = pin,
|
||||||
|
PinFile = pinFile,
|
||||||
|
UserName = user.Username
|
||||||
|
};
|
||||||
|
|
||||||
|
FileStream fileStream = AsyncFile.Create(pinFile);
|
||||||
|
await using (fileStream.ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ForgotPasswordResult
|
return new ForgotPasswordResult
|
||||||
{
|
{
|
||||||
Action = ForgotPasswordAction.PinCode,
|
Action = ForgotPasswordAction.PinCode,
|
||||||
PinExpirationDate = expireTime,
|
PinExpirationDate = expireTime,
|
||||||
PinFile = filePath
|
PinFile = pinFile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -508,23 +508,18 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
public async Task<ForgotPasswordResult> StartForgotPasswordProcess(string enteredUsername, bool isInNetwork)
|
public async Task<ForgotPasswordResult> StartForgotPasswordProcess(string enteredUsername, bool isInNetwork)
|
||||||
{
|
{
|
||||||
var user = string.IsNullOrWhiteSpace(enteredUsername) ? null : GetUserByName(enteredUsername);
|
var user = string.IsNullOrWhiteSpace(enteredUsername) ? null : GetUserByName(enteredUsername);
|
||||||
|
var passwordResetProvider = GetPasswordResetProvider(user);
|
||||||
|
|
||||||
|
var result = await passwordResetProvider
|
||||||
|
.StartForgotPasswordProcess(user, enteredUsername, isInNetwork)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (user is not null && isInNetwork)
|
if (user is not null && isInNetwork)
|
||||||
{
|
{
|
||||||
var passwordResetProvider = GetPasswordResetProvider(user);
|
|
||||||
var result = await passwordResetProvider
|
|
||||||
.StartForgotPasswordProcess(user, isInNetwork)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
await UpdateUserAsync(user).ConfigureAwait(false);
|
await UpdateUserAsync(user).ConfigureAwait(false);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ForgotPasswordResult
|
return result;
|
||||||
{
|
|
||||||
Action = ForgotPasswordAction.InNetworkRequired,
|
|
||||||
PinFile = string.Empty
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -760,8 +755,13 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
return GetAuthenticationProviders(user)[0];
|
return GetAuthenticationProviders(user)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPasswordResetProvider GetPasswordResetProvider(User user)
|
private IPasswordResetProvider GetPasswordResetProvider(User? user)
|
||||||
{
|
{
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
return _defaultPasswordResetProvider;
|
||||||
|
}
|
||||||
|
|
||||||
return GetPasswordResetProviders(user)[0];
|
return GetPasswordResetProviders(user)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
if (row.GetInt32(0) == 0)
|
if (row.GetInt32(0) == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Table 'ActivityLog' doesn't exist in {ActivityLogPath}, nothing to migrate", activityLogPath);
|
_logger.LogWarning("Table 'ActivityLog' doesn't exist in {ActivityLogPath}, nothing to migrate", activityLogPath);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,28 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
var dataPath = _appPaths.DataPath;
|
var dataPath = _appPaths.DataPath;
|
||||||
using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}"))
|
var dbFilePath = Path.Combine(dataPath, DbFilename);
|
||||||
|
|
||||||
|
if (!File.Exists(dbFilePath))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("{Path} doesn't exist, nothing to migrate", dbFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var connection = new SqliteConnection($"Filename={dbFilePath}"))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
|
var tableQuery = connection.Query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='Tokens';");
|
||||||
|
foreach (var row in tableQuery)
|
||||||
|
{
|
||||||
|
if (row.GetInt32(0) == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Table 'Tokens' doesn't exist in {Path}, nothing to migrate", dbFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using var dbContext = _dbProvider.CreateDbContext();
|
using var dbContext = _dbProvider.CreateDbContext();
|
||||||
|
|
||||||
var authenticatedDevices = connection.Query("SELECT * FROM Tokens");
|
var authenticatedDevices = connection.Query("SELECT * FROM Tokens");
|
||||||
|
|||||||
@@ -78,9 +78,27 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
var displayPrefs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var displayPrefs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var customDisplayPrefs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var customDisplayPrefs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var dbFilePath = Path.Combine(_paths.DataPath, DbFilename);
|
var dbFilePath = Path.Combine(_paths.DataPath, DbFilename);
|
||||||
|
|
||||||
|
if (!File.Exists(dbFilePath))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("{Path} doesn't exist, nothing to migrate", dbFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
using (var connection = new SqliteConnection($"Filename={dbFilePath}"))
|
using (var connection = new SqliteConnection($"Filename={dbFilePath}"))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
|
var tableQuery = connection.Query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='userdisplaypreferences';");
|
||||||
|
foreach (var row in tableQuery)
|
||||||
|
{
|
||||||
|
if (row.GetInt32(0) == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Table 'userdisplaypreferences' doesn't exist in {Path}, nothing to migrate", dbFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using var dbContext = _provider.CreateDbContext();
|
using var dbContext = _provider.CreateDbContext();
|
||||||
|
|
||||||
var results = connection.Query("SELECT * FROM userdisplaypreferences");
|
var results = connection.Query("SELECT * FROM userdisplaypreferences");
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public class MigrateUserDb : IMigrationRoutine
|
|||||||
if (row.GetInt32(0) == 0)
|
if (row.GetInt32(0) == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Table 'LocalUsersv2' doesn't exist in {UserDbPath}, nothing to migrate", userDbPath);
|
_logger.LogWarning("Table 'LocalUsersv2' doesn't exist in {UserDbPath}, nothing to migrate", userDbPath);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Common</PackageId>
|
<PackageId>Jellyfin.Common</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#nullable disable
|
|
||||||
|
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@@ -15,11 +13,12 @@ namespace MediaBrowser.Controller.Authentication
|
|||||||
|
|
||||||
bool IsEnabled { get; }
|
bool IsEnabled { get; }
|
||||||
|
|
||||||
Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork);
|
Task<ForgotPasswordResult> StartForgotPasswordProcess(User? user, string enteredUsername, bool isInNetwork);
|
||||||
|
|
||||||
Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
|
Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
public class PasswordPinCreationResult
|
public class PasswordPinCreationResult
|
||||||
{
|
{
|
||||||
public string PinFile { get; set; }
|
public string PinFile { get; set; }
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Controller</PackageId>
|
<PackageId>Jellyfin.Controller</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Model</PackageId>
|
<PackageId>Jellyfin.Model</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Users
|
namespace MediaBrowser.Model.Users
|
||||||
{
|
{
|
||||||
public enum ForgotPasswordAction
|
public enum ForgotPasswordAction
|
||||||
{
|
{
|
||||||
|
[Obsolete("Returning different actions represents a security concern.")]
|
||||||
ContactAdmin = 0,
|
ContactAdmin = 0,
|
||||||
PinCode = 1,
|
PinCode = 1,
|
||||||
|
[Obsolete("Returning different actions represents a security concern.")]
|
||||||
InNetworkRequired = 2
|
InNetworkRequired = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,6 +229,11 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
if (file is not null)
|
if (file is not null)
|
||||||
{
|
{
|
||||||
item.DateModified = file.LastWriteTimeUtc;
|
item.DateModified = file.LastWriteTimeUtc;
|
||||||
|
|
||||||
|
if (!file.IsDirectory)
|
||||||
|
{
|
||||||
|
item.Size = file.Length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("10.11.0")]
|
[assembly: AssemblyVersion("10.11.2")]
|
||||||
[assembly: AssemblyFileVersion("10.11.0")]
|
[assembly: AssemblyFileVersion("10.11.2")]
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ for subproject in ${jellyfin_subprojects[@]}; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Set the version in the GitHub issue template file
|
# Set the version in the GitHub issue template file
|
||||||
sed -i "s|${old_version}|${new_version_sed}|g" ${issue_template_file}
|
sed -i "s|${old_version}|${new_version_sed}|g" "${issue_template_file}"
|
||||||
|
|
||||||
# Stage the changed files for commit
|
# Stage the changed files for commit
|
||||||
git add .
|
git add .
|
||||||
|
|||||||
+6
-2
@@ -52,10 +52,14 @@ public class OptimisticLockBehavior : IEntityFrameworkCoreLockingBehavior
|
|||||||
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_writePolicy = Policy
|
_writePolicy = Policy
|
||||||
.HandleInner<Exception>(e => e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase))
|
.HandleInner<Exception>(e =>
|
||||||
|
e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
e.Message.Contains("database table is locked", StringComparison.InvariantCultureIgnoreCase))
|
||||||
.WaitAndRetry(sleepDurations.Length, backoffProvider, RetryHandle);
|
.WaitAndRetry(sleepDurations.Length, backoffProvider, RetryHandle);
|
||||||
_writeAsyncPolicy = Policy
|
_writeAsyncPolicy = Policy
|
||||||
.HandleInner<Exception>(e => e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase))
|
.HandleInner<Exception>(e =>
|
||||||
|
e.Message.Contains("database is locked", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
e.Message.Contains("database table is locked", StringComparison.InvariantCultureIgnoreCase))
|
||||||
.WaitAndRetryAsync(sleepDurations.Length, backoffProvider, RetryHandle);
|
.WaitAndRetryAsync(sleepDurations.Length, backoffProvider, RetryHandle);
|
||||||
|
|
||||||
void RetryHandle(Exception exception, TimeSpan timespan, int retryNo, Context context)
|
void RetryHandle(Exception exception, TimeSpan timespan, int retryNo, Context context)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Extensions</PackageId>
|
<PackageId>Jellyfin.Extensions</PackageId>
|
||||||
<VersionPrefix>10.11.0</VersionPrefix>
|
<VersionPrefix>10.11.2</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ public class SeasonPathParserTests
|
|||||||
[InlineData("/Drive/SPECIALS", "/Drive", 0, true)]
|
[InlineData("/Drive/SPECIALS", "/Drive", 0, true)]
|
||||||
[InlineData("/Drive/Episode 1 Season 2", "/Drive", null, false)]
|
[InlineData("/Drive/Episode 1 Season 2", "/Drive", null, false)]
|
||||||
[InlineData("/Drive/Episode 1 SEASON 2", "/Drive", null, false)]
|
[InlineData("/Drive/Episode 1 SEASON 2", "/Drive", null, false)]
|
||||||
|
[InlineData("/media/YouTube/Devyn Johnston/2024-01-24 4070 Ti SUPER in under 7 minutes", "/media/YouTube/Devyn Johnston", null, false)]
|
||||||
|
[InlineData("/media/YouTube/Devyn Johnston/2025-01-28 5090 vs 2 SFF Cases", "/media/YouTube/Devyn Johnston", null, false)]
|
||||||
|
[InlineData("/Drive/202401244070", "/Drive", null, false)]
|
||||||
public void GetSeasonNumberFromPathTest(string path, string? parentPath, int? seasonNumber, bool isSeasonDirectory)
|
public void GetSeasonNumberFromPathTest(string path, string? parentPath, int? seasonNumber, bool isSeasonDirectory)
|
||||||
{
|
{
|
||||||
var result = SeasonPathParser.Parse(path, parentPath, true, true);
|
var result = SeasonPathParser.Parse(path, parentPath, true, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user