mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-01-16 16:18:06 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5fe82314e | ||
|
|
06834fefef | ||
|
|
2946ae1009 | ||
|
|
4b8f735cb8 | ||
|
|
c230d49d7c | ||
|
|
20e2cb2d86 | ||
|
|
b70083f3b3 | ||
|
|
74ef389879 | ||
|
|
d78a55adb4 | ||
|
|
6f99ed3955 | ||
|
|
247a5e12ab | ||
|
|
855911333a | ||
|
|
127bfc7d3b | ||
|
|
7919dd81da | ||
|
|
e1da046960 | ||
|
|
a756026962 | ||
|
|
75260a960b | ||
|
|
69ee49bee6 | ||
|
|
1bf3a26a61 | ||
|
|
c5760b3a40 | ||
|
|
4de8bf3295 | ||
|
|
87c8f19f19 | ||
|
|
0ef52c739e | ||
|
|
0a9a6b949c | ||
|
|
c22068d6b1 | ||
|
|
bbc1a86b57 | ||
|
|
cd83d80f2b | ||
|
|
12721eb7dd | ||
|
|
b8a09339cd | ||
|
|
3634d367c1 | ||
|
|
c1daea0ec7 |
@@ -24,6 +24,7 @@
|
||||
- [Lynxy](https://github.com/Lynxy)
|
||||
- [fasheng](https://github.com/fasheng)
|
||||
- [ploughpuff](https://github.com/ploughpuff)
|
||||
- [pjeanjean](https://github.com/pjeanjean)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ RUN apt-get update \
|
||||
COPY --from=ffmpeg / /
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.2
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.5
|
||||
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& rm -rf /jellyfin/jellyfin-web \
|
||||
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
ARG DOTNET_VERSION=3.0
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||
FROM alpine as qemu_extract
|
||||
COPY --from=qemu /usr/bin qemu-arm-static.tar.gz
|
||||
RUN tar -xzvf qemu-arm-static.tar.gz
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
@@ -21,8 +16,9 @@ RUN bash -c "source deployment/common.build.sh && \
|
||||
build_jellyfin Jellyfin.Server Release linux-arm /jellyfin"
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-arm as qemu
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm32v7
|
||||
COPY --from=qemu_extract qemu-arm-static /usr/bin
|
||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
@@ -30,7 +26,7 @@ RUN apt-get update \
|
||||
&& chmod 777 /cache /config /media
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.2
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.5
|
||||
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& rm -rf /jellyfin/jellyfin-web \
|
||||
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
ARG DOTNET_VERSION=3.0
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||
FROM alpine as qemu_extract
|
||||
COPY --from=qemu /usr/bin qemu-aarch64-static.tar.gz
|
||||
RUN tar -xzvf qemu-aarch64-static.tar.gz
|
||||
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
@@ -22,8 +16,9 @@ RUN bash -c "source deployment/common.build.sh && \
|
||||
build_jellyfin Jellyfin.Server Release linux-arm64 /jellyfin"
|
||||
|
||||
|
||||
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}-stretch-slim-arm64v8
|
||||
COPY --from=qemu_extract qemu-aarch64-static /usr/bin
|
||||
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
@@ -31,7 +26,7 @@ RUN apt-get update \
|
||||
&& chmod 777 /cache /config /media
|
||||
COPY --from=builder /jellyfin /jellyfin
|
||||
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.2
|
||||
ARG JELLYFIN_WEB_VERSION=10.3.5
|
||||
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
|
||||
&& rm -rf /jellyfin/jellyfin-web \
|
||||
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
|
||||
|
||||
@@ -920,8 +920,6 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
|
||||
|
||||
if (!_profile.EnableSingleAlbumArtLimit || string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddImageResElement(item, writer, 4096, 4096, "jpg", "JPEG_LRG");
|
||||
@@ -930,6 +928,9 @@ namespace Emby.Dlna.Didl
|
||||
AddImageResElement(item, writer, 4096, 4096, "png", "PNG_LRG");
|
||||
AddImageResElement(item, writer, 160, 160, "png", "PNG_TN");
|
||||
}
|
||||
|
||||
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
|
||||
|
||||
}
|
||||
|
||||
private void AddEmbeddedImageAsCover(string name, XmlWriter writer)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.Library
|
||||
public string Name => "Default";
|
||||
|
||||
public bool IsEnabled => true;
|
||||
|
||||
|
||||
// This is dumb and an artifact of the backwards way auth providers were designed.
|
||||
// This version of authenticate was never meant to be called, but needs to be here for interface compat
|
||||
// Only the providers that don't provide local user support use this
|
||||
@@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
// This is the verson that we need to use for local users. Because reasons.
|
||||
public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
|
||||
{
|
||||
@@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.Library
|
||||
string hash = user.Password;
|
||||
user.Password = string.Format("$SHA1${0}", hash);
|
||||
}
|
||||
|
||||
|
||||
if (user.EasyPassword != null && !user.EasyPassword.Contains("$"))
|
||||
{
|
||||
string hash = user.EasyPassword;
|
||||
@@ -165,6 +165,34 @@ namespace Emby.Server.Implementations.Library
|
||||
return user.Password;
|
||||
}
|
||||
|
||||
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
|
||||
{
|
||||
ConvertPasswordFormat(user);
|
||||
|
||||
if (newPassword != null)
|
||||
{
|
||||
newPasswordHash = string.Format("$SHA1${0}", GetHashedString(user, newPassword));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(newPasswordHash))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(newPasswordHash));
|
||||
}
|
||||
|
||||
user.EasyPassword = newPasswordHash;
|
||||
}
|
||||
|
||||
public string GetEasyPasswordHash(User user)
|
||||
{
|
||||
// This should be removed in the future. This was added to let user login after
|
||||
// Jellyfin 10.3.3 failed to save a well formatted PIN.
|
||||
ConvertPasswordFormat(user);
|
||||
|
||||
return string.IsNullOrEmpty(user.EasyPassword)
|
||||
? null
|
||||
: (new PasswordHash(user.EasyPassword)).Hash;
|
||||
}
|
||||
|
||||
public string GetHashedStringChangeAuth(string newPassword, PasswordHash passwordHash)
|
||||
{
|
||||
passwordHash.HashBytes = Encoding.UTF8.GetBytes(newPassword);
|
||||
|
||||
47
Emby.Server.Implementations/Library/InvalidAuthProvider.cs
Normal file
47
Emby.Server.Implementations/Library/InvalidAuthProvider.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
public class InvalidAuthProvider : IAuthenticationProvider
|
||||
{
|
||||
public string Name => "InvalidOrMissingAuthenticationProvider";
|
||||
|
||||
public bool IsEnabled => true;
|
||||
|
||||
public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
|
||||
{
|
||||
throw new SecurityException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
|
||||
}
|
||||
|
||||
public Task<bool> HasPassword(User user)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public Task ChangePassword(User user, string newPassword)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
|
||||
{
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
public string GetPasswordHash(User user)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string GetEasyPasswordHash(User user)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,8 @@ namespace Emby.Server.Implementations.Library
|
||||
private IAuthenticationProvider[] _authenticationProviders;
|
||||
private DefaultAuthenticationProvider _defaultAuthenticationProvider;
|
||||
|
||||
private InvalidAuthProvider _invalidAuthProvider;
|
||||
|
||||
private IPasswordResetProvider[] _passwordResetProviders;
|
||||
private DefaultPasswordResetProvider _defaultPasswordResetProvider;
|
||||
|
||||
@@ -141,6 +143,8 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
_defaultAuthenticationProvider = _authenticationProviders.OfType<DefaultAuthenticationProvider>().First();
|
||||
|
||||
_invalidAuthProvider = _authenticationProviders.OfType<InvalidAuthProvider>().First();
|
||||
|
||||
_passwordResetProviders = passwordResetProviders.ToArray();
|
||||
|
||||
_defaultPasswordResetProvider = passwordResetProviders.OfType<DefaultPasswordResetProvider>().First();
|
||||
@@ -307,8 +311,7 @@ namespace Emby.Server.Implementations.Library
|
||||
user = Users
|
||||
.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var hasNewUserPolicy = authenticationProvider as IHasNewUserPolicy;
|
||||
if (hasNewUserPolicy != null)
|
||||
if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy)
|
||||
{
|
||||
var policy = hasNewUserPolicy.GetNewUserPolicy();
|
||||
UpdateUserPolicy(user, policy, true);
|
||||
@@ -400,7 +403,9 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (providers.Length == 0)
|
||||
{
|
||||
providers = new IAuthenticationProvider[] { _defaultAuthenticationProvider };
|
||||
// Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found
|
||||
_logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user.Name, user.Policy.AuthenticationProviderId);
|
||||
providers = new IAuthenticationProvider[] { _invalidAuthProvider };
|
||||
}
|
||||
|
||||
return providers;
|
||||
@@ -471,7 +476,7 @@ namespace Emby.Server.Implementations.Library
|
||||
if (password == null)
|
||||
{
|
||||
// legacy
|
||||
success = string.Equals(_defaultAuthenticationProvider.GetPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
|
||||
success = string.Equals(GetAuthenticationProvider(user).GetPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,11 +502,11 @@ namespace Emby.Server.Implementations.Library
|
||||
if (password == null)
|
||||
{
|
||||
// legacy
|
||||
success = string.Equals(GetLocalPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
|
||||
success = string.Equals(GetAuthenticationProvider(user).GetEasyPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = string.Equals(GetLocalPasswordHash(user), _defaultAuthenticationProvider.GetHashedString(user, password), StringComparison.OrdinalIgnoreCase);
|
||||
success = string.Equals(GetAuthenticationProvider(user).GetEasyPasswordHash(user), _defaultAuthenticationProvider.GetHashedString(user, password), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,13 +551,6 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
}
|
||||
|
||||
private string GetLocalPasswordHash(User user)
|
||||
{
|
||||
return string.IsNullOrEmpty(user.EasyPassword)
|
||||
? null
|
||||
: user.EasyPassword;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the users from the repository
|
||||
/// </summary>
|
||||
@@ -596,7 +594,7 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
|
||||
bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result;
|
||||
bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetLocalPasswordHash(user));
|
||||
bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetAuthenticationProvider(user).GetEasyPasswordHash(user));
|
||||
|
||||
bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
|
||||
hasConfiguredEasyPassword :
|
||||
@@ -884,17 +882,7 @@ namespace Emby.Server.Implementations.Library
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
if (newPassword != null)
|
||||
{
|
||||
newPasswordHash = _defaultAuthenticationProvider.GetHashedString(user, newPassword);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(newPasswordHash))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(newPasswordHash));
|
||||
}
|
||||
|
||||
user.EasyPassword = newPasswordHash;
|
||||
GetAuthenticationProvider(user).ChangeEasyPassword(user, newPassword, newPasswordHash);
|
||||
|
||||
UpdateUser(user);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Api.Movies;
|
||||
@@ -828,7 +830,16 @@ namespace MediaBrowser.Api.Library
|
||||
var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
|
||||
if (!string.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
headers[HeaderNames.ContentDisposition] = "attachment; filename=\"" + filename + "\"";
|
||||
// Kestrel doesn't support non-ASCII characters in headers
|
||||
if (Regex.IsMatch(filename, "[^[:ascii:]]"))
|
||||
{
|
||||
// Manually encoding non-ASCII characters, following https://tools.ietf.org/html/rfc5987#section-3.2.2
|
||||
headers[HeaderNames.ContentDisposition] = "attachment; filename*=UTF-8''" + WebUtility.UrlEncode(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
headers[HeaderNames.ContentDisposition] = "attachment; filename=\"" + filename + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
request.IncludeItemTypes = "Playlist";
|
||||
}
|
||||
|
||||
if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Any(i => new Guid(i) == item.Id))
|
||||
if (!(item is UserRootFolder) && !user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Any(i => new Guid(i) == item.Id))
|
||||
{
|
||||
Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Name, item.Name);
|
||||
return new QueryResult<BaseItem>
|
||||
|
||||
@@ -11,6 +11,9 @@ namespace MediaBrowser.Controller.Authentication
|
||||
Task<ProviderAuthenticationResult> Authenticate(string username, string password);
|
||||
Task<bool> HasPassword(User user);
|
||||
Task ChangePassword(User user, string newPassword);
|
||||
void ChangeEasyPassword(User user, string newPassword, string newPasswordHash);
|
||||
string GetPasswordHash(User user);
|
||||
string GetEasyPasswordHash(User user);
|
||||
}
|
||||
|
||||
public interface IRequiresResolvedUser
|
||||
|
||||
@@ -78,10 +78,25 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// The trailer folder name
|
||||
/// </summary>
|
||||
public static string TrailerFolderName = "trailers";
|
||||
public static string ThemeSongsFolderName = "theme-music";
|
||||
public static string ThemeSongFilename = "theme";
|
||||
public static string ThemeVideosFolderName = "backdrops";
|
||||
public const string TrailerFolderName = "trailers";
|
||||
public const string ThemeSongsFolderName = "theme-music";
|
||||
public const string ThemeSongFilename = "theme";
|
||||
public const string ThemeVideosFolderName = "backdrops";
|
||||
public const string ExtrasFolderName = "extras";
|
||||
public const string BehindTheScenesFolderName = "behind the scenes";
|
||||
public const string DeletedScenesFolderName = "deleted scenes";
|
||||
public const string InterviewFolderName = "interviews";
|
||||
public const string SceneFolderName = "scenes";
|
||||
public const string SampleFolderName = "samples";
|
||||
|
||||
public static readonly string[] AllExtrasTypesFolderNames = {
|
||||
ExtrasFolderName,
|
||||
BehindTheScenesFolderName,
|
||||
DeletedScenesFolderName,
|
||||
InterviewFolderName,
|
||||
SceneFolderName,
|
||||
SampleFolderName
|
||||
};
|
||||
|
||||
[IgnoreDataMember]
|
||||
public Guid[] ThemeSongIds { get; set; }
|
||||
@@ -1276,16 +1291,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
.Select(item =>
|
||||
{
|
||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||
var dbItem = LibraryManager.GetItemById(item.Id) as Video;
|
||||
|
||||
if (dbItem != null)
|
||||
if (LibraryManager.GetItemById(item.Id) is Video dbItem)
|
||||
{
|
||||
item = dbItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
// item is new
|
||||
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeVideo;
|
||||
item.ExtraType = Model.Entities.ExtraType.ThemeVideo;
|
||||
}
|
||||
|
||||
return item;
|
||||
@@ -1296,33 +1310,38 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
protected virtual BaseItem[] LoadExtras(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
|
||||
{
|
||||
var files = fileSystemChildren.Where(i => i.IsDirectory)
|
||||
.SelectMany(i => FileSystem.GetFiles(i.FullName));
|
||||
var extras = new List<Video>();
|
||||
|
||||
return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
|
||||
.OfType<Video>()
|
||||
.Select(item =>
|
||||
{
|
||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||
var dbItem = LibraryManager.GetItemById(item.Id) as Video;
|
||||
var folders = fileSystemChildren.Where(i => i.IsDirectory).ToArray();
|
||||
foreach (var extraFolderName in AllExtrasTypesFolderNames)
|
||||
{
|
||||
var files = folders
|
||||
.Where(i => string.Equals(i.Name, extraFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => FileSystem.GetFiles(i.FullName));
|
||||
|
||||
if (dbItem != null)
|
||||
extras.AddRange(LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
|
||||
.OfType<Video>()
|
||||
.Select(item =>
|
||||
{
|
||||
item = dbItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
// item is new
|
||||
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.Clip;
|
||||
}
|
||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||
if (LibraryManager.GetItemById(item.Id) is Video dbItem)
|
||||
{
|
||||
item = dbItem;
|
||||
}
|
||||
|
||||
return item;
|
||||
// Use some hackery to get the extra type based on foldername
|
||||
Enum.TryParse(extraFolderName.Replace(" ", ""), true, out ExtraType extraType);
|
||||
item.ExtraType = extraType;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToArray();
|
||||
return item;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path));
|
||||
}
|
||||
|
||||
return extras.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public Task RefreshMetadata(CancellationToken cancellationToken)
|
||||
{
|
||||
return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken);
|
||||
@@ -1481,7 +1500,13 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var newExtras = LoadExtras(fileSystemChildren, options.DirectoryService).Concat(LoadThemeVideos(fileSystemChildren, options.DirectoryService)).Concat(LoadThemeSongs(fileSystemChildren, options.DirectoryService));
|
||||
var extras = LoadExtras(fileSystemChildren, options.DirectoryService);
|
||||
var themeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
|
||||
var themeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
|
||||
var newExtras = new BaseItem[extras.Length + themeVideos.Length + themeSongs.Length];
|
||||
extras.CopyTo(newExtras, 0);
|
||||
themeVideos.CopyTo(newExtras, extras.Length);
|
||||
themeSongs.CopyTo(newExtras, extras.Length + themeVideos.Length);
|
||||
|
||||
var newExtraIds = newExtras.Select(i => i.Id).ToArray();
|
||||
|
||||
@@ -1493,7 +1518,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var tasks = newExtras.Select(i =>
|
||||
{
|
||||
return RefreshMetadataForOwnedItem(i, true, new MetadataRefreshOptions(options), cancellationToken);
|
||||
var subOptions = new MetadataRefreshOptions(options);
|
||||
if (i.OwnerId != ownerId || i.ParentId != Guid.Empty)
|
||||
{
|
||||
i.OwnerId = ownerId;
|
||||
i.ParentId = Guid.Empty;
|
||||
subOptions.ForceSave = true;
|
||||
}
|
||||
|
||||
return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB
|
||||
get
|
||||
{
|
||||
// Refresh if necessary
|
||||
if (_tokenCreatedAt > DateTime.Now.Subtract(TimeSpan.FromHours(20)))
|
||||
if (_tokenCreatedAt < DateTime.Now.Subtract(TimeSpan.FromHours(20)))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Submodule MediaBrowser.WebDashboard/jellyfin-web updated: 1ba58b06b3...37636dae5c
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("10.3.2")]
|
||||
[assembly: AssemblyFileVersion("10.3.2")]
|
||||
[assembly: AssemblyVersion("10.3.5")]
|
||||
[assembly: AssemblyFileVersion("10.3.5")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin"
|
||||
version: "10.3.2"
|
||||
version: "10.3.5"
|
||||
packages:
|
||||
- debian-package-x64
|
||||
- debian-package-armhf
|
||||
|
||||
@@ -18,3 +18,4 @@ rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/rpm
|
||||
mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -72,9 +72,6 @@ fi
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
|
||||
# Build the RPMs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the RPMs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}"
|
||||
# Move the RPMs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/rpm/* "${output_dir}"
|
||||
|
||||
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarm64
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -30,13 +30,12 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarmhf
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -30,13 +30,12 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
@@ -17,3 +17,4 @@ dpkg-buildpackage -us -uc
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -19,13 +19,12 @@ else
|
||||
docker_sudo=""
|
||||
fi
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
jellyfin (10.3.5-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.3.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.5
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 09 Jun 2019 21:47:35 -0400
|
||||
|
||||
jellyfin (10.3.4-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.3.4; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.4
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Thu, 06 Jun 2019 22:45:31 -0400
|
||||
|
||||
jellyfin (10.3.3-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.3.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.3
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 17 May 2019 23:12:08 -0400
|
||||
|
||||
jellyfin (10.3.2-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.3.2; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.2
|
||||
|
||||
@@ -18,3 +18,4 @@ rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/rpm
|
||||
mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -23,13 +23,12 @@ fi
|
||||
|
||||
./create_tarball.sh
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
|
||||
# Build the RPMs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the RPMs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}"
|
||||
# Move the RPMs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/rpm/* "${output_dir}"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%endif
|
||||
|
||||
Name: jellyfin
|
||||
Version: 10.3.2
|
||||
Version: 10.3.5
|
||||
Release: 1%{?dist}
|
||||
Summary: The Free Software Media Browser
|
||||
License: GPLv2
|
||||
@@ -140,6 +140,12 @@ fi
|
||||
%systemd_postun_with_restart jellyfin.service
|
||||
|
||||
%changelog
|
||||
* Sun Jun 09 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.3.5; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.5
|
||||
* Thu Jun 06 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.3.4; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.4
|
||||
* Fri May 17 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.3.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.3
|
||||
* Tue Apr 30 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.3.2; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.2
|
||||
* Sat Apr 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
|
||||
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarm64
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -30,13 +30,12 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarmhf
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -30,13 +30,12 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
@@ -17,3 +17,4 @@ dpkg-buildpackage -us -uc
|
||||
# Move the artifacts out
|
||||
mkdir -p ${ARTIFACT_DIR}/deb
|
||||
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
|
||||
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
|
||||
|
||||
@@ -19,13 +19,12 @@ else
|
||||
docker_sudo=""
|
||||
fi
|
||||
|
||||
# Prepare temporary package dir
|
||||
mkdir -p "${package_temporary_dir}"
|
||||
# Set up the build environment Docker image
|
||||
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
|
||||
# Build the DEBs and copy out to ${package_temporary_dir}
|
||||
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
|
||||
# Correct ownership on the DEBs (as current user, then as root if that fails)
|
||||
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|
||||
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
|
||||
# Move the DEBs to the output directory
|
||||
mkdir -p "${output_dir}"
|
||||
mv "${package_temporary_dir}"/deb/* "${output_dir}"
|
||||
|
||||
Reference in New Issue
Block a user