aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile2
-rw-r--r--Dockerfile.arm2
-rw-r--r--Dockerfile.arm642
-rw-r--r--Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs6
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs4
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs13
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs25
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs91
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs37
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs2
m---------MediaBrowser.WebDashboard/jellyfin-web0
-rw-r--r--SharedVersion.cs4
-rw-r--r--build.yaml4
-rwxr-xr-xdeployment/centos-package-x64/docker-build.sh1
-rwxr-xr-xdeployment/centos-package-x64/package.sh3
-rw-r--r--deployment/debian-package-arm64/Dockerfile.amd6443
-rw-r--r--deployment/debian-package-arm64/Dockerfile.arm6434
-rwxr-xr-xdeployment/debian-package-arm64/clean.sh29
-rw-r--r--deployment/debian-package-arm64/dependencies.txt1
-rwxr-xr-xdeployment/debian-package-arm64/docker-build.sh21
-rwxr-xr-xdeployment/debian-package-arm64/package.sh41
l---------deployment/debian-package-arm64/pkg-src1
-rwxr-xr-xdeployment/debian-package-armhf/docker-build.sh1
-rwxr-xr-xdeployment/debian-package-armhf/package.sh5
-rwxr-xr-xdeployment/debian-package-x64/docker-build.sh1
-rwxr-xr-xdeployment/debian-package-x64/package.sh5
-rw-r--r--deployment/debian-package-x64/pkg-src/changelog6
-rw-r--r--deployment/debian-package-x64/pkg-src/rules13
-rwxr-xr-xdeployment/fedora-package-x64/docker-build.sh1
-rwxr-xr-xdeployment/fedora-package-x64/package.sh5
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.spec4
-rw-r--r--deployment/ubuntu-package-arm64/Dockerfile.amd6453
-rw-r--r--deployment/ubuntu-package-arm64/Dockerfile.arm6434
-rwxr-xr-xdeployment/ubuntu-package-arm64/clean.sh29
-rw-r--r--deployment/ubuntu-package-arm64/dependencies.txt1
-rwxr-xr-xdeployment/ubuntu-package-arm64/docker-build.sh21
-rwxr-xr-xdeployment/ubuntu-package-arm64/package.sh41
l---------deployment/ubuntu-package-arm64/pkg-src1
-rwxr-xr-xdeployment/ubuntu-package-armhf/docker-build.sh1
-rwxr-xr-xdeployment/ubuntu-package-armhf/package.sh5
-rwxr-xr-xdeployment/ubuntu-package-x64/docker-build.sh1
-rwxr-xr-xdeployment/ubuntu-package-x64/package.sh5
44 files changed, 498 insertions, 105 deletions
diff --git a/Dockerfile b/Dockerfile
index 3242003e1..f414995f7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,7 +21,7 @@ RUN apt-get update \
COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.1
+ARG JELLYFIN_WEB_VERSION=10.3.2
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
diff --git a/Dockerfile.arm b/Dockerfile.arm
index 3cec9133f..66f731354 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -30,7 +30,7 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.1
+ARG JELLYFIN_WEB_VERSION=10.3.2
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
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 476ef2929..690d4b6e7 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -31,7 +31,7 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.1
+ARG JELLYFIN_WEB_VERSION=10.3.2
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
diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
index 3d15a8afb..0527464ff 100644
--- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
+++ b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
@@ -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;
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 952cc6896..b396ee51a 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -550,7 +550,7 @@ namespace Emby.Server.Implementations.Library
{
return string.IsNullOrEmpty(user.EasyPassword)
? null
- : user.EasyPassword;
+ : (new PasswordHash(user.EasyPassword)).Hash;
}
/// <summary>
@@ -596,7 +596,7 @@ namespace Emby.Server.Implementations.Library
}
bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result;
- bool hasConfiguredEasyPassword = string.IsNullOrEmpty(GetLocalPasswordHash(user));
+ bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetLocalPasswordHash(user));
bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
hasConfiguredEasyPassword :
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 8eefbdf2c..9f8da9c16 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -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
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 1c36289c5..83a3f3e3c 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -283,8 +283,6 @@ namespace MediaBrowser.Api.Playback.Progressive
{
state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent);
- const bool trySupportSeek = false;
-
var options = new HttpRequestOptions
{
Url = state.MediaPath,
@@ -293,30 +291,9 @@ namespace MediaBrowser.Api.Playback.Progressive
CancellationToken = cancellationTokenSource.Token
};
- if (trySupportSeek)
- {
- if (!string.IsNullOrWhiteSpace(Request.QueryString[HeaderNames.Range]))
- {
- options.RequestHeaders[HeaderNames.Range] = Request.QueryString[HeaderNames.Range];
- }
- }
var response = await HttpClient.GetResponse(options).ConfigureAwait(false);
- if (trySupportSeek)
- {
- foreach (var name in new[] { HeaderNames.ContentRange, HeaderNames.AcceptRanges })
- {
- var val = response.Headers[name];
- if (!string.IsNullOrWhiteSpace(val))
- {
- responseHeaders[name] = val;
- }
- }
- }
- else
- {
- responseHeaders[HeaderNames.AcceptRanges] = "none";
- }
+ responseHeaders[HeaderNames.AcceptRanges] = "none";
// Seeing cases of -1 here
if (response.ContentLength.HasValue && response.ContentLength.Value >= 0)
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index e20641c99..10a603e42 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -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,32 +1310,37 @@ 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)
- {
- item = dbItem;
- }
- else
+ extras.AddRange(LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
+ .OfType<Video>()
+ .Select(item =>
{
- // 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)
{
@@ -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);
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index b626600fa..a8874b6d0 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -53,7 +53,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly int DefaultImageExtractionTimeoutMs;
private readonly string StartupOptionFFmpegPath;
- private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1);
+ private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
private readonly ILocalizationManager _localization;
@@ -582,19 +582,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
bool ranToCompletion;
- StartProcess(processWrapper);
-
- var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
- if (timeoutMs <= 0)
+ await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+ try
{
- timeoutMs = DefaultImageExtractionTimeoutMs;
- }
+ StartProcess(processWrapper);
+
+ var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
+ if (timeoutMs <= 0)
+ {
+ timeoutMs = DefaultImageExtractionTimeoutMs;
+ }
- ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
+ ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
- if (!ranToCompletion)
+ if (!ranToCompletion)
+ {
+ StopProcess(processWrapper, 1000);
+ }
+ }
+ finally
{
- StopProcess(processWrapper, 1000);
+ _thumbnailResourcePool.Release();
}
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
@@ -625,7 +633,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
return time.ToString(@"hh\:mm\:ss\.fff", UsCulture);
}
- public async Task ExtractVideoImagesOnInterval(string[] inputFiles,
+ public async Task ExtractVideoImagesOnInterval(
+ string[] inputFiles,
string container,
MediaStream videoStream,
MediaProtocol protocol,
@@ -636,8 +645,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
int? maxWidth,
CancellationToken cancellationToken)
{
- var resourcePool = _thumbnailResourcePool;
-
var inputArgument = GetInputArgument(inputFiles, protocol);
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture);
@@ -701,7 +708,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
- await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+ await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
bool ranToCompletion = false;
@@ -742,7 +749,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
finally
{
- resourcePool.Release();
+ _thumbnailResourcePool.Release();
}
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index 3797f9039..179e953f4 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -336,7 +336,7 @@ namespace MediaBrowser.Providers.Music
}
using (var subReader = reader.ReadSubtree())
{
- return ParseReleaseList(subReader);
+ return ParseReleaseList(subReader).ToList();
}
}
default:
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 59280df89..728f7731a 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Music
}
using (var subReader = reader.ReadSubtree())
{
- return ParseArtistList(subReader);
+ return ParseArtistList(subReader).ToList();
}
}
default:
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
index 5474a7c39..302d40c6b 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB
/// <summary>
/// Class RemoteEpisodeProvider
/// </summary>
- class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
+ public class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
{
private readonly IHttpClient _httpClient;
private readonly ILogger _logger;
diff --git a/MediaBrowser.WebDashboard/jellyfin-web b/MediaBrowser.WebDashboard/jellyfin-web
-Subproject 97f6808e12243bbb9b58344185511a9369913c0
+Subproject 1ba58b06b3dc28e07abae124cff78aa656fcb7e
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 9120f988c..700ef4549 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("10.3.1")]
-[assembly: AssemblyFileVersion("10.3.1")]
+[assembly: AssemblyVersion("10.3.2")]
+[assembly: AssemblyFileVersion("10.3.2")]
diff --git a/build.yaml b/build.yaml
index 0f843bf74..8ce6a00a8 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1,12 +1,14 @@
---
# We just wrap `build` so this is really it
name: "jellyfin"
-version: "10.3.1"
+version: "10.3.2"
packages:
- debian-package-x64
- debian-package-armhf
+ - debian-package-arm64
- ubuntu-package-x64
- ubuntu-package-armhf
+ - ubuntu-package-arm64
- fedora-package-x64
- centos-package-x64
- linux-x64
diff --git a/deployment/centos-package-x64/docker-build.sh b/deployment/centos-package-x64/docker-build.sh
index 3acf1ec0d..cefb1652e 100755
--- a/deployment/centos-package-x64/docker-build.sh
+++ b/deployment/centos-package-x64/docker-build.sh
@@ -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}
diff --git a/deployment/centos-package-x64/package.sh b/deployment/centos-package-x64/package.sh
index 27d686e46..df5a66580 100755
--- a/deployment/centos-package-x64/package.sh
+++ b/deployment/centos-package-x64/package.sh
@@ -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}"
diff --git a/deployment/debian-package-arm64/Dockerfile.amd64 b/deployment/debian-package-arm64/Dockerfile.amd64
new file mode 100644
index 000000000..2cb8bd856
--- /dev/null
+++ b/deployment/debian-package-arm64/Dockerfile.amd64
@@ -0,0 +1,43 @@
+FROM debian:9
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+ENV DEB_BUILD_OPTIONS=noddebs
+ENV ARCH=amd64
+
+# Prepare Debian build environment
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/69937b49-a877-4ced-81e6-286620b390ab/8ab938cf6f5e83b2221630354160ef21/dotnet-sdk-2.2.104-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+ && mkdir -p dotnet-sdk \
+ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
+ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+
+# Prepare the cross-toolchain
+RUN dpkg --add-architecture arm64 \
+ && apt-get update \
+ && apt-get install -y cross-gcc-dev \
+ && TARGET_LIST="arm64" cross-gcc-gensource 6 \
+ && cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \
+ && apt-get install -y gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+# Link to Debian source dir; mkdir needed or it fails, can't force dest
+RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
+#ENTRYPOINT ["/bin/bash"]
diff --git a/deployment/debian-package-arm64/Dockerfile.arm64 b/deployment/debian-package-arm64/Dockerfile.arm64
new file mode 100644
index 000000000..bb9e28d0a
--- /dev/null
+++ b/deployment/debian-package-arm64/Dockerfile.arm64
@@ -0,0 +1,34 @@
+FROM debian:9
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+ENV DEB_BUILD_OPTIONS=noddebs
+ENV ARCH=arm64
+
+# Prepare Debian build environment
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev liblttng-ust0
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/d9f37b73-df8d-4dfa-a905-b7648d3401d0/6312573ac13d7a8ddc16e4058f7d7dc5/dotnet-sdk-2.2.104-linux-arm.tar.gz -O dotnet-sdk.tar.gz \
+ && mkdir -p dotnet-sdk \
+ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
+ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+# Link to Debian source dir; mkdir needed or it fails, can't force dest
+RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/debian-package-arm64/clean.sh b/deployment/debian-package-arm64/clean.sh
new file mode 100755
index 000000000..ac143c3d0
--- /dev/null
+++ b/deployment/debian-package-arm64/clean.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+keep_artifacts="${1}"
+
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-debian_arm64-build"
+
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/debian-package-arm64/dependencies.txt b/deployment/debian-package-arm64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/debian-package-arm64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/debian-package-arm64/docker-build.sh b/deployment/debian-package-arm64/docker-build.sh
new file mode 100755
index 000000000..cee96e136
--- /dev/null
+++ b/deployment/debian-package-arm64/docker-build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Builds the DEB inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
+sed -i '/dotnet-sdk-2.2,/d' debian/control
+
+# Build DEB
+export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
+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}
diff --git a/deployment/debian-package-arm64/package.sh b/deployment/debian-package-arm64/package.sh
new file mode 100755
index 000000000..ce02b1af5
--- /dev/null
+++ b/deployment/debian-package-arm64/package.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+ARCH="$( arch )"
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-debian_arm64-build"
+
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
+fi
+
+# Determine which Dockerfile to use
+case $ARCH in
+ 'x86_64')
+ DOCKERFILE="Dockerfile.amd64"
+ ;;
+ 'armv7l')
+ DOCKERFILE="Dockerfile.arm64"
+ ;;
+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}"
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/debian-package-arm64/pkg-src b/deployment/debian-package-arm64/pkg-src
new file mode 120000
index 000000000..4c695fea1
--- /dev/null
+++ b/deployment/debian-package-arm64/pkg-src
@@ -0,0 +1 @@
+../debian-package-x64/pkg-src \ No newline at end of file
diff --git a/deployment/debian-package-armhf/docker-build.sh b/deployment/debian-package-armhf/docker-build.sh
index 45e68f0c6..56227b588 100755
--- a/deployment/debian-package-armhf/docker-build.sh
+++ b/deployment/debian-package-armhf/docker-build.sh
@@ -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}
diff --git a/deployment/debian-package-armhf/package.sh b/deployment/debian-package-armhf/package.sh
index 0ec0dc95c..4393fb834 100755
--- a/deployment/debian-package-armhf/package.sh
+++ b/deployment/debian-package-armhf/package.sh
@@ -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}"
diff --git a/deployment/debian-package-x64/docker-build.sh b/deployment/debian-package-x64/docker-build.sh
index 0590be097..07f726dcc 100755
--- a/deployment/debian-package-x64/docker-build.sh
+++ b/deployment/debian-package-x64/docker-build.sh
@@ -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}
diff --git a/deployment/debian-package-x64/package.sh b/deployment/debian-package-x64/package.sh
index d7c3f5809..2530e253b 100755
--- a/deployment/debian-package-x64/package.sh
+++ b/deployment/debian-package-x64/package.sh
@@ -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}"
diff --git a/deployment/debian-package-x64/pkg-src/changelog b/deployment/debian-package-x64/pkg-src/changelog
index ce30ca6f6..61977c4e0 100644
--- a/deployment/debian-package-x64/pkg-src/changelog
+++ b/deployment/debian-package-x64/pkg-src/changelog
@@ -1,3 +1,9 @@
+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
+
+ -- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 30 Apr 2019 20:18:44 -0400
+
jellyfin (10.3.1-1) unstable; urgency=medium
* New upstream version 10.3.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.1
diff --git a/deployment/debian-package-x64/pkg-src/rules b/deployment/debian-package-x64/pkg-src/rules
index 62f75bc6b..ee41e0e24 100644
--- a/deployment/debian-package-x64/pkg-src/rules
+++ b/deployment/debian-package-x64/pkg-src/rules
@@ -6,18 +6,25 @@ SHELL := /bin/bash
HOST_ARCH := $(shell arch)
BUILD_ARCH := ${DEB_HOST_MULTIARCH}
ifeq ($(HOST_ARCH),x86_64)
+ # Building AMD64
+ DOTNETRUNTIME := debian-x64
ifeq ($(BUILD_ARCH),arm-linux-gnueabihf)
# Cross-building ARM on AMD64
DOTNETRUNTIME := debian-arm
- else
- # Building AMD64
- DOTNETRUNTIME := debian-x64
+ endif
+ ifeq ($(BUILD_ARCH),aarch64-linux-gnu)
+ # Cross-building ARM on AMD64
+ DOTNETRUNTIME := debian-arm64
endif
endif
ifeq ($(HOST_ARCH),armv7l)
# Building ARM
DOTNETRUNTIME := debian-arm
endif
+ifeq ($(HOST_ARCH),arm64)
+ # Building ARM
+ DOTNETRUNTIME := debian-arm64
+endif
export DH_VERBOSE=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1
diff --git a/deployment/fedora-package-x64/docker-build.sh b/deployment/fedora-package-x64/docker-build.sh
index 3acf1ec0d..cefb1652e 100755
--- a/deployment/fedora-package-x64/docker-build.sh
+++ b/deployment/fedora-package-x64/docker-build.sh
@@ -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}
diff --git a/deployment/fedora-package-x64/package.sh b/deployment/fedora-package-x64/package.sh
index eed29aef3..e659ee5e9 100755
--- a/deployment/fedora-package-x64/package.sh
+++ b/deployment/fedora-package-x64/package.sh
@@ -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}"
diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
index 0d938aef9..58d643569 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
@@ -7,7 +7,7 @@
%endif
Name: jellyfin
-Version: 10.3.1
+Version: 10.3.2
Release: 1%{?dist}
Summary: The Free Software Media Browser
License: GPLv2
@@ -140,6 +140,8 @@ fi
%systemd_postun_with_restart jellyfin.service
%changelog
+* 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>
- New upstream version 10.3.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.1
* Fri Apr 19 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
diff --git a/deployment/ubuntu-package-arm64/Dockerfile.amd64 b/deployment/ubuntu-package-arm64/Dockerfile.amd64
new file mode 100644
index 000000000..5e51ef0f0
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/Dockerfile.amd64
@@ -0,0 +1,53 @@
+FROM ubuntu:bionic
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+ENV DEB_BUILD_OPTIONS=noddebs
+ENV ARCH=amd64
+
+# Prepare Debian build environment
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/69937b49-a877-4ced-81e6-286620b390ab/8ab938cf6f5e83b2221630354160ef21/dotnet-sdk-2.2.104-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
+ && mkdir -p dotnet-sdk \
+ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
+ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+
+# Prepare the cross-toolchain
+RUN rm /etc/apt/sources.list \
+ && export CODENAME="$( lsb_release -c -s )" \
+ && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
+ && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
+ && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
+ && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
+ && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
+ && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
+ && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
+ && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
+ && dpkg --add-architecture arm64 \
+ && apt-get update \
+ && apt-get install -y cross-gcc-dev \
+ && TARGET_LIST="arm64" cross-gcc-gensource 6 \
+ && cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \
+ && ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \
+ && apt-get install -y gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+# Link to Debian source dir; mkdir needed or it fails, can't force dest
+RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/ubuntu-package-arm64/Dockerfile.arm64 b/deployment/ubuntu-package-arm64/Dockerfile.arm64
new file mode 100644
index 000000000..646679328
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/Dockerfile.arm64
@@ -0,0 +1,34 @@
+FROM ubuntu:bionic
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64
+ARG ARTIFACT_DIR=/dist
+ARG SDK_VERSION=2.2
+# Docker run environment
+ENV SOURCE_DIR=/jellyfin
+ENV ARTIFACT_DIR=/dist
+ENV DEB_BUILD_OPTIONS=noddebs
+ENV ARCH=arm64
+
+# Prepare Debian build environment
+RUN apt-get update \
+ && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev liblttng-ust0
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/d9f37b73-df8d-4dfa-a905-b7648d3401d0/6312573ac13d7a8ddc16e4058f7d7dc5/dotnet-sdk-2.2.104-linux-arm.tar.gz -O dotnet-sdk.tar.gz \
+ && mkdir -p dotnet-sdk \
+ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
+ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+# Link to Debian source dir; mkdir needed or it fails, can't force dest
+RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/ubuntu-package-arm64/clean.sh b/deployment/ubuntu-package-arm64/clean.sh
new file mode 100755
index 000000000..c92c7fdec
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/clean.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+keep_artifacts="${1}"
+
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-ubuntu-build"
+
+rm -rf "${package_temporary_dir}" &>/dev/null \
+ || sudo rm -rf "${package_temporary_dir}" &>/dev/null
+
+rm -rf "${output_dir}" &>/dev/null \
+ || sudo rm -rf "${output_dir}" &>/dev/null
+
+if [[ ${keep_artifacts} == 'n' ]]; then
+ docker_sudo=""
+ if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo=sudo
+ fi
+ ${docker_sudo} docker image rm ${image_name} --force
+fi
diff --git a/deployment/ubuntu-package-arm64/dependencies.txt b/deployment/ubuntu-package-arm64/dependencies.txt
new file mode 100644
index 000000000..bdb967096
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/dependencies.txt
@@ -0,0 +1 @@
+docker
diff --git a/deployment/ubuntu-package-arm64/docker-build.sh b/deployment/ubuntu-package-arm64/docker-build.sh
new file mode 100755
index 000000000..cee96e136
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/docker-build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Builds the DEB inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
+sed -i '/dotnet-sdk-2.2,/d' debian/control
+
+# Build DEB
+export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
+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}
diff --git a/deployment/ubuntu-package-arm64/package.sh b/deployment/ubuntu-package-arm64/package.sh
new file mode 100755
index 000000000..5a2bf61c8
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/package.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+source ../common.build.sh
+
+ARCH="$( arch )"
+WORKDIR="$( pwd )"
+
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-ubuntu_arm64-build"
+
+# Determine if sudo should be used for Docker
+if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
+ && [[ ! ${EUID:-1000} -eq 0 ]] \
+ && [[ ! ${USER} == "root" ]] \
+ && [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
+ docker_sudo="sudo"
+else
+ docker_sudo=""
+fi
+
+# Determine which Dockerfile to use
+case $ARCH in
+ 'x86_64')
+ DOCKERFILE="Dockerfile.amd64"
+ ;;
+ 'armv7l')
+ DOCKERFILE="Dockerfile.arm64"
+ ;;
+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}"
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/ubuntu-package-arm64/pkg-src b/deployment/ubuntu-package-arm64/pkg-src
new file mode 120000
index 000000000..4c695fea1
--- /dev/null
+++ b/deployment/ubuntu-package-arm64/pkg-src
@@ -0,0 +1 @@
+../debian-package-x64/pkg-src \ No newline at end of file
diff --git a/deployment/ubuntu-package-armhf/docker-build.sh b/deployment/ubuntu-package-armhf/docker-build.sh
index 45e68f0c6..56227b588 100755
--- a/deployment/ubuntu-package-armhf/docker-build.sh
+++ b/deployment/ubuntu-package-armhf/docker-build.sh
@@ -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}
diff --git a/deployment/ubuntu-package-armhf/package.sh b/deployment/ubuntu-package-armhf/package.sh
index fb03652cd..15f55bff2 100755
--- a/deployment/ubuntu-package-armhf/package.sh
+++ b/deployment/ubuntu-package-armhf/package.sh
@@ -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}"
diff --git a/deployment/ubuntu-package-x64/docker-build.sh b/deployment/ubuntu-package-x64/docker-build.sh
index 0590be097..07f726dcc 100755
--- a/deployment/ubuntu-package-x64/docker-build.sh
+++ b/deployment/ubuntu-package-x64/docker-build.sh
@@ -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}
diff --git a/deployment/ubuntu-package-x64/package.sh b/deployment/ubuntu-package-x64/package.sh
index 6d4625a19..32e6d4fd6 100755
--- a/deployment/ubuntu-package-x64/package.sh
+++ b/deployment/ubuntu-package-x64/package.sh
@@ -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}"