mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-13 20:43:03 +03:00
Compare commits
19 Commits
| 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",
|
"**/small.jpg",
|
||||||
"**/albumart.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
|
// Directories
|
||||||
"**/metadata/**",
|
"**/metadata/**",
|
||||||
@@ -64,10 +78,13 @@ namespace Emby.Server.Implementations.Library
|
|||||||
"**/.grab/**",
|
"**/.grab/**",
|
||||||
"**/.grab",
|
"**/.grab",
|
||||||
|
|
||||||
// Unix hidden files and directories
|
// Unix hidden files
|
||||||
"**/.*/**",
|
|
||||||
"**/.*",
|
"**/.*",
|
||||||
|
|
||||||
|
// Mac - if you ever remove the above.
|
||||||
|
// "**/._*",
|
||||||
|
// "**/.DS_Store",
|
||||||
|
|
||||||
// thumbs.db
|
// thumbs.db
|
||||||
"**/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();
|
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);
|
RegisterItem(item);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -152,7 +152,12 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
return true;
|
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) ||
|
if ((octet[0] == 10) ||
|
||||||
(octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918
|
(octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918
|
||||||
@@ -268,6 +273,12 @@ namespace Emby.Server.Implementations.Networking
|
|||||||
string excludeAddress = "[" + addressString + "]";
|
string excludeAddress = "[" + addressString + "]";
|
||||||
var subnets = LocalSubnetsFn();
|
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 [ ]
|
// Exclude any addresses if they appear in the LAN list in [ ]
|
||||||
if (Array.IndexOf(subnets, excludeAddress) != -1)
|
if (Array.IndexOf(subnets, excludeAddress) != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Jellyfin.Data;
|
using Jellyfin.Data;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
@@ -133,6 +134,18 @@ namespace Jellyfin.Server.Implementations
|
|||||||
return base.SaveChanges();
|
return base.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var entry in ChangeTracker.Entries())
|
||||||
|
{
|
||||||
|
entry.State = EntityState.Detached;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
base.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -102,7 +102,16 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <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/>
|
/// <inheritdoc/>
|
||||||
public User? GetUserById(Guid id)
|
public User? GetUserById(Guid id)
|
||||||
@@ -152,12 +161,12 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
throw new ArgumentException("Invalid username", nameof(newName));
|
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.");
|
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(
|
throw new ArgumentException(string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@@ -637,7 +646,7 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void UpdateConfiguration(Guid userId, UserConfiguration config)
|
public void UpdateConfiguration(Guid userId, UserConfiguration config)
|
||||||
{
|
{
|
||||||
var dbContext = _dbProvider.CreateContext();
|
using var dbContext = _dbProvider.CreateContext();
|
||||||
var user = dbContext.Users
|
var user = dbContext.Users
|
||||||
.Include(u => u.Permissions)
|
.Include(u => u.Permissions)
|
||||||
.Include(u => u.Preferences)
|
.Include(u => u.Preferences)
|
||||||
@@ -670,7 +679,7 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void UpdatePolicy(Guid userId, UserPolicy policy)
|
public void UpdatePolicy(Guid userId, UserPolicy policy)
|
||||||
{
|
{
|
||||||
var dbContext = _dbProvider.CreateContext();
|
using var dbContext = _dbProvider.CreateContext();
|
||||||
var user = dbContext.Users
|
var user = dbContext.Users
|
||||||
.Include(u => u.Permissions)
|
.Include(u => u.Permissions)
|
||||||
.Include(u => u.Preferences)
|
.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 @
|
// 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
|
// 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 (.)
|
// 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\-'._@]*$");
|
return Regex.IsMatch(name, @"^[\w\ \-'._@]*$");
|
||||||
}
|
}
|
||||||
|
|
||||||
private IAuthenticationProvider GetAuthenticationProvider(User user)
|
private IAuthenticationProvider GetAuthenticationProvider(User user)
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ namespace Jellyfin.Server.Migrations
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether to perform migration on a new install.
|
||||||
|
/// </summary>
|
||||||
|
public bool PerformOnNewInstall { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execute the migration routine.
|
/// Execute the migration routine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations
|
|||||||
typeof(Routines.MigrateActivityLogDb),
|
typeof(Routines.MigrateActivityLogDb),
|
||||||
typeof(Routines.RemoveDuplicateExtras),
|
typeof(Routines.RemoveDuplicateExtras),
|
||||||
typeof(Routines.AddDefaultPluginRepository),
|
typeof(Routines.AddDefaultPluginRepository),
|
||||||
typeof(Routines.MigrateUserDb)
|
typeof(Routines.MigrateUserDb),
|
||||||
|
typeof(Routines.ReaddDefaultPluginRepository)
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -43,9 +44,8 @@ namespace Jellyfin.Server.Migrations
|
|||||||
// If startup wizard is not finished, this is a fresh install.
|
// If startup wizard is not finished, this is a fresh install.
|
||||||
// Don't run any migrations, just mark all of them as applied.
|
// 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");
|
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);
|
host.ServerConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name => "AddDefaultPluginRepository";
|
public string Name => "AddDefaultPluginRepository";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => true;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name => "CreateLoggingConfigHeirarchy";
|
public string Name => "CreateLoggingConfigHeirarchy";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name => "DisableTranscodingThrottling";
|
public string Name => "DisableTranscodingThrottling";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name => "MigrateActivityLogDatabase";
|
public string Name => "MigrateActivityLogDatabase";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name => "MigrateUserDatabase";
|
public string Name => "MigrateUserDatabase";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
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/>
|
/// <inheritdoc/>
|
||||||
public string Name => "RemoveDuplicateExtras";
|
public string Name => "RemoveDuplicateExtras";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool PerformOnNewInstall => false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -456,11 +456,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||||
|
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
|
|
||||||
if (!IsCopyCodec(outputVideoCodec))
|
if (!IsCopyCodec(outputVideoCodec))
|
||||||
{
|
{
|
||||||
if (state.IsVideoRequest
|
if (state.IsVideoRequest
|
||||||
&& IsVaapiSupported(state)
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
||||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
&& string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (isVaapiDecoder)
|
if (isVaapiDecoder)
|
||||||
@@ -495,13 +496,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arg.Append("-hwaccel qsv -init_hw_device qsv=hw ");
|
arg.Append("-hwaccel qsv ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWindows)
|
if (isWindows)
|
||||||
{
|
{
|
||||||
arg.Append("-hwaccel qsv -init_hw_device qsv=hw ");
|
arg.Append("-hwaccel qsv ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// While using SW decoder
|
// 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 ")
|
arg.Append("-i ")
|
||||||
@@ -1606,25 +1613,41 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
|
index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
outputSizeParam = outputSizeParam.Substring(index);
|
outputSizeParam = outputSizeParam.Substring(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
|
index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
outputSizeParam = outputSizeParam.Substring(index);
|
outputSizeParam = outputSizeParam.Substring(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
|
index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
outputSizeParam = outputSizeParam.Substring(index);
|
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
|
// 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))
|
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -1790,6 +1813,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var outputWidth = width.Value;
|
var outputWidth = width.Value;
|
||||||
var outputHeight = height.Value;
|
var outputHeight = height.Value;
|
||||||
var qsv_or_vaapi = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase);
|
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
|
if (!videoWidth.HasValue
|
||||||
|| outputWidth != videoWidth.Value
|
|| outputWidth != videoWidth.Value
|
||||||
@@ -1805,7 +1832,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi",
|
qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi",
|
||||||
outputWidth,
|
outputWidth,
|
||||||
outputHeight,
|
outputHeight,
|
||||||
(qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty));
|
(qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1814,7 +1841,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
"{0}=format=nv12{1}",
|
"{0}=format=nv12{1}",
|
||||||
qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi",
|
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
|
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/
|
// http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/
|
||||||
|
|
||||||
var request = state.BaseRequest;
|
var request = state.BaseRequest;
|
||||||
|
|
||||||
var videoStream = state.VideoStream;
|
var videoStream = state.VideoStream;
|
||||||
var filters = new List<string>();
|
var filters = new List<string>();
|
||||||
|
|
||||||
@@ -2035,23 +2061,31 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var inputHeight = videoStream?.Height;
|
var inputHeight = videoStream?.Height;
|
||||||
var threeDFormat = state.MediaSource.Video3DFormat;
|
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
|
// 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("format=nv12|vaapi");
|
||||||
filters.Add("hwupload");
|
filters.Add("hwupload");
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the input may or may not be hardware QSV decodable
|
// When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context
|
||||||
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
else if (isLinux && hasGraphicalSubs && isQsvH264Encoder)
|
||||||
{
|
{
|
||||||
filters.Add("format=nv12|qsv");
|
|
||||||
filters.Add("hwupload=extra_hw_frames=64");
|
filters.Add("hwupload=extra_hw_frames=64");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
|
// 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 (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder)
|
||||||
&& string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
var codec = videoStream.Codec.ToLowerInvariant();
|
var codec = videoStream.Codec.ToLowerInvariant();
|
||||||
var isColorDepth10 = IsColorDepth10(state);
|
var isColorDepth10 = IsColorDepth10(state);
|
||||||
@@ -2079,16 +2113,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add hardware deinterlace filter before scaling filter
|
// 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"));
|
filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add software deinterlace filter before scaling filter
|
// 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 deintParam = string.Empty;
|
||||||
var inputFramerate = videoStream?.RealFrameRate;
|
var inputFramerate = videoStream?.RealFrameRate;
|
||||||
@@ -2105,9 +2142,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(deintParam))
|
if (!string.IsNullOrEmpty(deintParam))
|
||||||
{
|
{
|
||||||
if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder)
|
||||||
&& !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
|
||||||
&& videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1)
|
|
||||||
{
|
{
|
||||||
filters.Add(deintParam);
|
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
|
// 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));
|
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)
|
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
|
||||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
if (isVaapiH264Encoder)
|
||||||
{
|
{
|
||||||
if (state.SubtitleStream != null
|
if (hasTextSubs)
|
||||||
&& state.SubtitleStream.IsTextSubtitleStream
|
|
||||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
|
||||||
{
|
{
|
||||||
// Test passed on Intel and AMD gfx
|
// Test passed on Intel and AMD gfx
|
||||||
filters.Add("hwmap=mode=read+write");
|
filters.Add("hwmap=mode=read+write");
|
||||||
@@ -2132,9 +2165,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (state.SubtitleStream != null
|
if (hasTextSubs)
|
||||||
&& state.SubtitleStream.IsTextSubtitleStream
|
|
||||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
|
||||||
{
|
{
|
||||||
var subParam = GetTextSubtitleParam(state);
|
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
|
// Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API
|
||||||
// Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI
|
// Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI
|
||||||
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
|
if (isVaapiH264Encoder)
|
||||||
{
|
{
|
||||||
filters.Add("hwmap");
|
filters.Add("hwmap");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,7 +172,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||||||
inputFiles = new[] { mediaSource.Path };
|
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);
|
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
|
// 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 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 = "";
|
encodingParam = "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#pragma warning disable CA1819 // Properties should not return arrays
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@@ -9,21 +10,27 @@ namespace MediaBrowser.Model.Notifications
|
|||||||
public NotificationOption(string type)
|
public NotificationOption(string type)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
|
|
||||||
DisabledServices = Array.Empty<string>();
|
DisabledServices = Array.Empty<string>();
|
||||||
DisabledMonitorUsers = Array.Empty<string>();
|
DisabledMonitorUsers = Array.Empty<string>();
|
||||||
SendToUsers = 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>
|
/// <summary>
|
||||||
/// User Ids to not monitor (it's opt out).
|
/// Gets or sets user Ids to not monitor (it's opt out).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] DisabledMonitorUsers { get; set; }
|
public string[] DisabledMonitorUsers { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User Ids to send to (if SendToUserMode == Custom)
|
/// Gets or sets user Ids to send to (if SendToUserMode == Custom).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] SendToUsers { get; set; }
|
public string[] SendToUsers { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -28,29 +28,31 @@
|
|||||||
pluginId: "a629c0da-fac5-4c7e-931a-7174223f14c8"
|
pluginId: "a629c0da-fac5-4c7e-931a-7174223f14c8"
|
||||||
};
|
};
|
||||||
|
|
||||||
$('.configPage').on('pageshow', function () {
|
document.querySelector('.configPage')
|
||||||
Dashboard.showLoadingMsg();
|
.addEventListener('pageshow', function () {
|
||||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
Dashboard.showLoadingMsg();
|
||||||
$('#enable').checked = config.Enable;
|
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||||
$('#replaceAlbumName').checked = config.ReplaceAlbumName;
|
document.querySelector('#enable').checked = config.Enable;
|
||||||
|
document.querySelector('#replaceAlbumName').checked = config.ReplaceAlbumName;
|
||||||
Dashboard.hideLoadingMsg();
|
|
||||||
});
|
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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
|||||||
|
|
||||||
public override string Description => "Get artist and album metadata or images from 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)
|
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||||
: base(applicationPaths, xmlSerializer)
|
: base(applicationPaths, xmlSerializer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,33 +36,47 @@
|
|||||||
uniquePluginId: "8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a"
|
uniquePluginId: "8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a"
|
||||||
};
|
};
|
||||||
|
|
||||||
$('.musicBrainzConfigPage').on('pageshow', function () {
|
document.querySelector('.musicBrainzConfigPage')
|
||||||
Dashboard.showLoadingMsg();
|
.addEventListener('pageshow', function () {
|
||||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
Dashboard.showLoadingMsg();
|
||||||
$('#server').val(config.Server).change();
|
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||||
$('#rateLimit').val(config.RateLimit).change();
|
var server = document.querySelector('#server');
|
||||||
$('#enable').checked = config.Enable;
|
server.value = config.Server;
|
||||||
$('#replaceArtistName').checked = config.ReplaceArtistName;
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
document.querySelector('.musicBrainzConfigForm')
|
||||||
$('.musicBrainzConfigForm').on('submit', function (e) {
|
.addEventListener('submit', function (e) {
|
||||||
Dashboard.showLoadingMsg();
|
Dashboard.showLoadingMsg();
|
||||||
|
|
||||||
var form = this;
|
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
||||||
ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
|
config.Server = document.querySelector('#server').value;
|
||||||
config.Server = $('#server', form).val();
|
config.RateLimit = document.querySelector('#rateLimit').value;
|
||||||
config.RateLimit = $('#rateLimit', form).val();
|
config.Enable = document.querySelector('#enable').checked;
|
||||||
config.Enable = $('#enable', form).checked;
|
config.ReplaceArtistName = document.querySelector('#replaceArtistName').checked;
|
||||||
config.ReplaceArtistName = $('#replaceArtistName', form).checked;
|
|
||||||
|
ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||||
ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
});
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ namespace MediaBrowser.Providers.Plugins.MusicBrainz
|
|||||||
|
|
||||||
public const long DefaultRateLimit = 2000u;
|
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)
|
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||||
: base(applicationPaths, xmlSerializer)
|
: base(applicationPaths, xmlSerializer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,25 +24,28 @@
|
|||||||
pluginId: "a628c0da-fac5-4c7e-9d1a-7134223f14c8"
|
pluginId: "a628c0da-fac5-4c7e-9d1a-7134223f14c8"
|
||||||
};
|
};
|
||||||
|
|
||||||
$('.configPage').on('pageshow', function () {
|
document.querySelector('.configPage')
|
||||||
Dashboard.showLoadingMsg();
|
.addEventListener('pageshow', function () {
|
||||||
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
Dashboard.showLoadingMsg();
|
||||||
$('#castAndCrew').checked = config.CastAndCrew;
|
ApiClient.getPluginConfiguration(PluginConfig.pluginId).then(function (config) {
|
||||||
Dashboard.hideLoadingMsg();
|
document.querySelector('#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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb
|
|||||||
|
|
||||||
public override string Description => "Get metadata for movies and other video content from 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)
|
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||||
: base(applicationPaths, 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.";
|
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)
|
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
|
||||||
: base(applicationPaths, xmlSerializer)
|
: base(applicationPaths, xmlSerializer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("10.6.0")]
|
[assembly: AssemblyVersion("10.6.1")]
|
||||||
[assembly: AssemblyFileVersion("10.6.0")]
|
[assembly: AssemblyFileVersion("10.6.1")]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
# We just wrap `build` so this is really it
|
# We just wrap `build` so this is really it
|
||||||
name: "jellyfin"
|
name: "jellyfin"
|
||||||
version: "10.6.0"
|
version: "10.6.1"
|
||||||
packages:
|
packages:
|
||||||
- debian.amd64
|
- debian.amd64
|
||||||
- debian.arm64
|
- 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
|
jellyfin-server (10.6.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Forthcoming stable release
|
* 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"
|
#JELLYFIN_SERVICE_OPT="--service"
|
||||||
|
|
||||||
# [OPTIONAL] run Jellyfin without the web app
|
# [OPTIONAL] run Jellyfin without the web app
|
||||||
#JELLYFIN_NOWEBAPP_OPT="--noautorunwebapp"
|
#JELLYFIN_NOWEBAPP_OPT="--nowebclient"
|
||||||
|
|
||||||
#
|
#
|
||||||
# SysV init/Upstart options
|
# SysV init/Upstart options
|
||||||
@@ -40,4 +40,4 @@ JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg"
|
|||||||
# Application username
|
# Application username
|
||||||
JELLYFIN_USER="jellyfin"
|
JELLYFIN_USER="jellyfin"
|
||||||
# Full application command
|
# 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
|
Vcs-Browser: https://github.org/jellyfin/jellyfin
|
||||||
|
|
||||||
Package: jellyfin-server
|
Package: jellyfin-server
|
||||||
Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
Replaces: jellyfin (<<10.6.0)
|
||||||
Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
Breaks: jellyfin (<<10.6.0)
|
||||||
Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
|
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: at,
|
Depends: at,
|
||||||
libsqlite3-0,
|
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
|
Standards-Version: 3.9.2
|
||||||
|
|
||||||
Package: jellyfin
|
Package: jellyfin
|
||||||
Version: 10.6.0
|
Version: 10.6.1
|
||||||
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
|
Maintainer: Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||||
Depends: jellyfin-server, jellyfin-web
|
Depends: jellyfin-server, jellyfin-web
|
||||||
Description: Provides the Jellyfin Free Software Media System
|
Description: Provides the Jellyfin Free Software Media System
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
Name: jellyfin
|
Name: jellyfin
|
||||||
Version: 10.6.0
|
Version: 10.6.1
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: The Free Software Media System
|
Summary: The Free Software Media System
|
||||||
License: GPLv3
|
License: GPLv3
|
||||||
@@ -139,6 +139,8 @@ fi
|
|||||||
%systemd_postun_with_restart jellyfin.service
|
%systemd_postun_with_restart jellyfin.service
|
||||||
|
|
||||||
%changelog
|
%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>
|
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||||
- Forthcoming stable release
|
- Forthcoming stable release
|
||||||
* Fri Oct 11 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
* 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/small.jpg", true)]
|
||||||
[InlineData("/media/albumart.jpg", true)]
|
[InlineData("/media/albumart.jpg", true)]
|
||||||
[InlineData("/media/movie.sample.mp4", 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/test.txt", true)]
|
||||||
[InlineData("/media/movies/#recycle/", true)]
|
[InlineData("/media/movies/#recycle/", true)]
|
||||||
[InlineData("/media/movies/#recycle", true)]
|
[InlineData("/media/movies/#recycle", true)]
|
||||||
[InlineData("thumbs.db", true)]
|
[InlineData("thumbs.db", true)]
|
||||||
[InlineData(@"C:\media\movies\movie.avi", false)]
|
[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/.hiddenfile.mp4", true)]
|
||||||
|
[InlineData("/media/dir/._macjunk.mp4", true)]
|
||||||
[InlineData("/volume1/video/Series/@eaDir", true)]
|
[InlineData("/volume1/video/Series/@eaDir", true)]
|
||||||
[InlineData("/volume1/video/Series/@eaDir/file.txt", true)]
|
[InlineData("/volume1/video/Series/@eaDir/file.txt", true)]
|
||||||
[InlineData("/directory/@Recycle", true)]
|
[InlineData("/directory/@Recycle", true)]
|
||||||
[InlineData("/directory/@Recycle/file.mp3", 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)
|
public void PathIgnored(string path, bool expected)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected, IgnorePatterns.ShouldIgnore(path));
|
Assert.Equal(expected, IgnorePatterns.ShouldIgnore(path));
|
||||||
|
|||||||
Reference in New Issue
Block a user