aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines.yml4
-rw-r--r--.github/pull_request_template.md2
-rw-r--r--.github/stale.yml2
-rw-r--r--Dockerfile14
-rw-r--r--Dockerfile.arm3
-rw-r--r--Dockerfile.arm643
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs134
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs4
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs2
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs8
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs30
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json60
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json48
-rw-r--r--Emby.Server.Implementations/Localization/Core/ko.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/sl-SI.json10
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs11
-rw-r--r--Jellyfin.Server/Program.cs10
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs3
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs23
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs4
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs8
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs294
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs21
-rw-r--r--MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs2
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/System/PublicSystemInfo.cs8
-rw-r--r--MediaBrowser.sln7
-rw-r--r--README.md10
-rwxr-xr-xbuild36
-rwxr-xr-xbump_version27
-rw-r--r--deployment/README.md57
-rw-r--r--deployment/centos-package-x64/Dockerfile21
-rwxr-xr-xdeployment/centos-package-x64/clean.sh2
-rwxr-xr-xdeployment/centos-package-x64/docker-build.sh64
-rwxr-xr-xdeployment/centos-package-x64/package.sh57
-rwxr-xr-xdeployment/common.build.sh110
-rw-r--r--deployment/debian-package-arm64/Dockerfile.amd646
-rwxr-xr-xdeployment/debian-package-arm64/clean.sh2
-rwxr-xr-xdeployment/debian-package-arm64/docker-build.sh14
-rwxr-xr-xdeployment/debian-package-arm64/package.sh8
-rw-r--r--deployment/debian-package-armhf/Dockerfile.amd646
-rw-r--r--deployment/debian-package-armhf/Dockerfile.armhf6
-rwxr-xr-xdeployment/debian-package-armhf/clean.sh2
-rwxr-xr-xdeployment/debian-package-armhf/docker-build.sh14
-rwxr-xr-xdeployment/debian-package-armhf/package.sh8
-rw-r--r--deployment/debian-package-x64/Dockerfile6
-rwxr-xr-xdeployment/debian-package-x64/clean.sh2
-rwxr-xr-xdeployment/debian-package-x64/docker-build.sh14
-rwxr-xr-xdeployment/debian-package-x64/package.sh8
-rw-r--r--deployment/debian-package-x64/pkg-src/changelog294
-rwxr-xr-xdeployment/docker/build.sh12
-rwxr-xr-xdeployment/docker/package.sh12
-rw-r--r--deployment/fedora-package-x64/Dockerfile22
-rwxr-xr-xdeployment/fedora-package-x64/clean.sh2
-rwxr-xr-xdeployment/fedora-package-x64/create_tarball.sh55
-rwxr-xr-xdeployment/fedora-package-x64/docker-build.sh64
-rwxr-xr-xdeployment/fedora-package-x64/package.sh12
-rw-r--r--deployment/fedora-package-x64/pkg-src/jellyfin.spec210
-rw-r--r--deployment/linux-x64/Dockerfile37
-rwxr-xr-xdeployment/linux-x64/build.sh7
-rwxr-xr-xdeployment/linux-x64/clean.sh26
-rw-r--r--deployment/linux-x64/dependencies.txt2
-rwxr-xr-xdeployment/linux-x64/docker-build.sh36
-rwxr-xr-xdeployment/linux-x64/package.sh33
-rw-r--r--deployment/macos/Dockerfile37
-rwxr-xr-xdeployment/macos/build.sh7
-rwxr-xr-xdeployment/macos/clean.sh26
-rw-r--r--deployment/macos/dependencies.txt2
-rwxr-xr-xdeployment/macos/docker-build.sh36
-rwxr-xr-xdeployment/macos/package.sh33
-rw-r--r--deployment/portable/Dockerfile37
-rwxr-xr-xdeployment/portable/build.sh8
-rwxr-xr-xdeployment/portable/clean.sh26
-rw-r--r--deployment/portable/dependencies.txt (renamed from deployment/docker/dependencies.txt)0
-rwxr-xr-xdeployment/portable/docker-build.sh36
-rwxr-xr-xdeployment/portable/package.sh33
-rw-r--r--deployment/ubuntu-package-arm64/Dockerfile.amd646
-rwxr-xr-xdeployment/ubuntu-package-arm64/clean.sh2
-rwxr-xr-xdeployment/ubuntu-package-arm64/docker-build.sh14
-rwxr-xr-xdeployment/ubuntu-package-arm64/package.sh8
-rw-r--r--deployment/ubuntu-package-armhf/Dockerfile.amd646
-rw-r--r--deployment/ubuntu-package-armhf/Dockerfile.armhf6
-rwxr-xr-xdeployment/ubuntu-package-armhf/clean.sh2
-rwxr-xr-xdeployment/ubuntu-package-armhf/docker-build.sh14
-rwxr-xr-xdeployment/ubuntu-package-armhf/package.sh8
-rw-r--r--deployment/ubuntu-package-x64/Dockerfile6
-rwxr-xr-xdeployment/ubuntu-package-x64/clean.sh2
-rwxr-xr-xdeployment/ubuntu-package-x64/docker-build.sh14
-rwxr-xr-xdeployment/ubuntu-package-x64/package.sh8
-rw-r--r--deployment/win-x64/Dockerfile37
-rwxr-xr-xdeployment/win-x64/build.sh7
-rwxr-xr-xdeployment/win-x64/clean.sh26
-rw-r--r--deployment/win-x64/dependencies.txt2
-rwxr-xr-xdeployment/win-x64/docker-build.sh61
-rwxr-xr-xdeployment/win-x64/package.sh71
-rw-r--r--deployment/win-x86/Dockerfile37
-rwxr-xr-xdeployment/win-x86/build.sh7
-rwxr-xr-xdeployment/win-x86/clean.sh26
-rw-r--r--deployment/win-x86/dependencies.txt2
-rwxr-xr-xdeployment/win-x86/docker-build.sh61
-rwxr-xr-xdeployment/win-x86/package.sh71
-rw-r--r--deployment/windows/build-jellyfin.ps14
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj2
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs45
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs66
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj19
107 files changed, 1538 insertions, 1411 deletions
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index 6c95ad4ce..46c478b08 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -34,7 +34,7 @@ jobs:
displayName: "Check out web"
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
- script: 'git clone --single-branch --branch $(Build.SourceBranch) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
+ script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: CmdLine@2
displayName: "Check out web (PR)"
@@ -203,7 +203,7 @@ jobs:
displayName: "Check out web"
condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
inputs:
- script: 'git clone --single-branch --branch $(Build.SourceBranch) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
+ script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
- task: CmdLine@2
displayName: "Check out web (PR)"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 967be0fb7..dc93d2c84 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,6 +1,6 @@
<!--
Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y).
-For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page.
+For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our documentation.
-->
**Changes**
diff --git a/.github/stale.yml b/.github/stale.yml
index ce9fb01a1..9ea0e3796 100644
--- a/.github/stale.yml
+++ b/.github/stale.yml
@@ -17,6 +17,6 @@ staleLabel: stale
markComment: >
Issues go stale after 90d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 14d of inactivity.
If this issue is safe to close now please do so.
- If you have any questions you can reach us on [Matrix or Social Media](https://jellyfin.readthedocs.io/en/latest/getting-help/).
+ If you have any questions you can reach us on [Matrix or Social Media](https://docs.jellyfin.org/general/getting-help.html).
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
diff --git a/Dockerfile b/Dockerfile
index 483345e39..a45576868 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,12 +14,17 @@ FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
WORKDIR /repo
COPY . .
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
-RUN bash -c "source deployment/common.build.sh && \
- build_jellyfin Jellyfin.Server Release linux-x64 /jellyfin"
+RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
+
FROM mcr.microsoft.com/dotnet/core/runtime:${DOTNET_VERSION}
-# libfontconfig1 is required for Skia
+COPY --from=ffmpeg / /
+COPY --from=builder /jellyfin /jellyfin
+COPY --from=web-builder /dist /jellyfin/jellyfin-web
+# Install dependencies:
+# libfontconfig1: needed for Skia
+# mesa-va-drivers: needed for VAAPI
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
libfontconfig1 mesa-va-drivers \
@@ -28,9 +33,6 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /cache /config /media \
&& chmod 777 /cache /config /media
-COPY --from=ffmpeg / /
-COPY --from=builder /jellyfin /jellyfin
-COPY --from=web-builder /dist /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Dockerfile.arm b/Dockerfile.arm
index 8a91d71be..742e050d5 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -22,8 +22,7 @@ RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
-RUN bash -c "source deployment/common.build.sh && \
- build_jellyfin Jellyfin.Server Release linux-arm /jellyfin"
+RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
FROM multiarch/qemu-user-static:x86_64-arm as qemu
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index b24d5d599..8c0baf925 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -22,8 +22,7 @@ RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
-RUN bash -c "source deployment/common.build.sh && \
- build_jellyfin Jellyfin.Server Release linux-arm64 /jellyfin"
+RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 24f59478c..f36d465dd 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -615,11 +615,34 @@ namespace Emby.Server.Implementations
var host = new WebHostBuilder()
.UseKestrel(options =>
{
- options.ListenAnyIP(HttpPort);
+ var addresses = ServerConfigurationManager
+ .Configuration
+ .LocalNetworkAddresses
+ .Select(NormalizeConfiguredLocalAddress)
+ .Where(i => i != null)
+ .ToList();
+ if (addresses.Any())
+ {
+ foreach (var address in addresses)
+ {
+ Logger.LogInformation("Kestrel listening on {ipaddr}", address);
+ options.Listen(address, HttpPort);
- if (EnableHttps && Certificate != null)
+ if (EnableHttps && Certificate != null)
+ {
+ options.Listen(address, HttpsPort, listenOptions => listenOptions.UseHttps(Certificate));
+ }
+ }
+ }
+ else
{
- options.ListenAnyIP(HttpsPort, listenOptions => listenOptions.UseHttps(Certificate));
+ Logger.LogInformation("Kestrel listening on all interfaces");
+ options.ListenAnyIP(HttpPort);
+
+ if (EnableHttps && Certificate != null)
+ {
+ options.ListenAnyIP(HttpsPort, listenOptions => listenOptions.UseHttps(Certificate));
+ }
}
})
.UseContentRoot(contentRoot)
@@ -640,7 +663,15 @@ namespace Emby.Server.Implementations
})
.Build();
- await host.StartAsync().ConfigureAwait(false);
+ try
+ {
+ await host.StartAsync().ConfigureAwait(false);
+ }
+ catch
+ {
+ Logger.LogError("Kestrel failed to start! This is most likely due to an invalid address or port bind - correct your bind configuration in system.xml and try again.");
+ throw;
+ }
}
private async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next)
@@ -1198,25 +1229,11 @@ namespace Emby.Server.Implementations
private CertificateInfo GetCertificateInfo(bool generateCertificate)
{
- if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath))
- {
- // Custom cert
- return new CertificateInfo
- {
- Path = ServerConfigurationManager.Configuration.CertificatePath,
- Password = ServerConfigurationManager.Configuration.CertificatePassword
- };
- }
-
- // Generate self-signed cert
- var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
- var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N", CultureInfo.InvariantCulture) + ".pfx");
- const string Password = "embycert";
-
+ // Custom cert
return new CertificateInfo
{
- Path = certPath,
- Password = Password
+ Path = ServerConfigurationManager.Configuration.CertificatePath,
+ Password = ServerConfigurationManager.Configuration.CertificatePassword
};
}
@@ -1403,17 +1420,6 @@ namespace Emby.Server.Implementations
{
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
- string wanAddress;
-
- if (string.IsNullOrEmpty(ServerConfigurationManager.Configuration.WanDdns))
- {
- wanAddress = await GetWanApiUrlFromExternal(cancellationToken).ConfigureAwait(false);
- }
- else
- {
- wanAddress = GetWanApiUrl(ServerConfigurationManager.Configuration.WanDdns);
- }
-
return new SystemInfo
{
HasPendingRestart = HasPendingRestart,
@@ -1435,7 +1441,6 @@ namespace Emby.Server.Implementations
OperatingSystemDisplayName = OperatingSystem.Name,
CanSelfRestart = CanSelfRestart,
CanLaunchWebBrowser = CanLaunchWebBrowser,
- WanAddress = wanAddress,
HasUpdateAvailable = HasUpdateAvailable,
TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
ServerName = FriendlyName,
@@ -1457,24 +1462,12 @@ namespace Emby.Server.Implementations
{
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
- string wanAddress;
-
- if (string.IsNullOrEmpty(ServerConfigurationManager.Configuration.WanDdns))
- {
- wanAddress = await GetWanApiUrlFromExternal(cancellationToken).ConfigureAwait(false);
- }
- else
- {
- wanAddress = GetWanApiUrl(ServerConfigurationManager.Configuration.WanDdns);
- }
-
return new PublicSystemInfo
{
Version = ApplicationVersion,
ProductName = ApplicationProductName,
Id = SystemId,
OperatingSystem = OperatingSystem.Id.ToString(),
- WanAddress = wanAddress,
ServerName = FriendlyName,
LocalAddress = localAddress
};
@@ -1506,31 +1499,6 @@ namespace Emby.Server.Implementations
return null;
}
- public async Task<string> GetWanApiUrlFromExternal(CancellationToken cancellationToken)
- {
- const string Url = "http://ipv4.icanhazip.com";
- try
- {
- using (var response = await HttpClient.Get(new HttpRequestOptions
- {
- Url = Url,
- LogErrorResponseBody = false,
- BufferContent = false,
- CancellationToken = cancellationToken
- }).ConfigureAwait(false))
- {
- string res = await response.ReadToEndAsync().ConfigureAwait(false);
- return GetWanApiUrl(res.Trim());
- }
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error getting WAN Ip address information");
- }
-
- return null;
- }
-
/// <summary>
/// Removes the scope id from IPv6 addresses.
/// </summary>
@@ -1573,32 +1541,6 @@ namespace Emby.Server.Implementations
HttpPort.ToString(CultureInfo.InvariantCulture));
}
- public string GetWanApiUrl(IPAddress ipAddress)
- {
- if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
- {
- var str = RemoveScopeId(ipAddress.ToString());
-
- return GetWanApiUrl("[" + str + "]");
- }
-
- return GetWanApiUrl(ipAddress.ToString());
- }
-
- public string GetWanApiUrl(string host)
- {
- if (EnableHttps)
- {
- return string.Format("https://{0}:{1}",
- host,
- ServerConfigurationManager.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture));
- }
-
- return string.Format("http://{0}:{1}",
- host,
- ServerConfigurationManager.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture));
- }
-
public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)
{
return GetLocalIpAddressesInternal(true, 0, cancellationToken);
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index a5bb47afb..4e392f6c9 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -53,10 +53,10 @@ namespace Emby.Server.Implementations.Data
protected virtual int? CacheSize => null;
/// <summary>
- /// Gets the journal mode.
+ /// Gets the journal mode. <see href="https://www.sqlite.org/pragma.html#pragma_journal_mode" />
/// </summary>
/// <value>The journal mode.</value>
- protected virtual string JournalMode => "WAL";
+ protected virtual string JournalMode => "TRUNCATE";
/// <summary>
/// Gets the page size.
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 2f083dda4..96f90b831 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -2724,7 +2724,7 @@ namespace Emby.Server.Implementations.Data
if (elapsed >= SlowThreshold)
{
- Logger.LogWarning(
+ Logger.LogDebug(
"{Method} query time (slow): {ElapsedMs}ms. Query: {Query}",
methodName,
elapsed,
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index a3201f0bc..6c0e32e05 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1099,7 +1099,9 @@ namespace Emby.Server.Implementations.Dto
Series episodeSeries = null;
- if (options.ContainsField(ItemFields.SeriesPrimaryImage))
+ // this block will add the series poster for episodes without a poster
+ // TODO maybe remove the if statement entirely
+ //if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{
episodeSeries = episodeSeries ?? episode.Series;
if (episodeSeries != null)
@@ -1143,7 +1145,9 @@ namespace Emby.Server.Implementations.Dto
}
}
- if (options.ContainsField(ItemFields.SeriesPrimaryImage))
+ // this block will add the series poster for seasons without a poster
+ // TODO maybe remove the if statement entirely
+ //if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{
series = series ?? season.Series;
if (series != null)
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index bdcf5d0b7..d60f5c055 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <returns></returns>
public void ApplyRequestFilters(IRequest req, HttpResponse res, object requestDto)
{
- //Exec all RequestFilter attributes with Priority < 0
+ // Exec all RequestFilter attributes with Priority < 0
var attributes = GetRequestFilterAttributes(requestDto.GetType());
int count = attributes.Count;
@@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.HttpServer
attribute.RequestFilter(req, res, requestDto);
}
- //Exec remaining RequestFilter attributes with Priority >= 0
+ // Exec remaining RequestFilter attributes with Priority >= 0
for (; i < count && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
@@ -276,9 +276,9 @@ namespace Emby.Server.Implementations.HttpServer
{
connection.Dispose();
}
- catch
+ catch (Exception ex)
{
-
+ _logger.LogError(ex, "Error disposing connection");
}
}
}
@@ -603,7 +603,14 @@ namespace Emby.Server.Implementations.HttpServer
Summary = route.Summary
});
- routes.Add(new RouteAttribute(NormalizeOldRoutePath(route.Path), route.Verbs)
+ routes.Add(new RouteAttribute(NormalizeEmbyRoutePath(route.Path), route.Verbs)
+ {
+ Notes = route.Notes,
+ Priority = route.Priority,
+ Summary = route.Summary
+ });
+
+ routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs)
{
Notes = route.Notes,
Priority = route.Priority,
@@ -645,7 +652,7 @@ namespace Emby.Server.Implementations.HttpServer
}
// this method was left for compatibility with third party clients
- private static string NormalizeOldRoutePath(string path)
+ private static string NormalizeEmbyRoutePath(string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
{
@@ -655,6 +662,17 @@ namespace Emby.Server.Implementations.HttpServer
return "emby/" + path;
}
+ // this method was left for compatibility with third party clients
+ private static string NormalizeMediaBrowserRoutePath(string path)
+ {
+ if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
+ {
+ return "/mediabrowser" + path;
+ }
+
+ return "mediabrowser/" + path;
+ }
+
private static string NormalizeCustomRoutePath(string baseUrl, string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index eb145b4fe..4da3cdd3b 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -1,22 +1,22 @@
{
- "Albums": "الألبومات",
- "AppDeviceValues": "التطبيق: {0}. الجهاز: {1}.",
+ "Albums": "ألبومات",
+ "AppDeviceValues": "تطبيق: {0}, جهاز: {1}",
"Application": "التطبيق",
- "Artists": "الفنانون",
- "AuthenticationSucceededWithUserName": "تم التأكد من {0} بنجاح",
- "Books": "الكتب",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+ "Artists": "الفنان",
+ "AuthenticationSucceededWithUserName": "{0} سجل الدخول بنجاح",
+ "Books": "كتب",
+ "CameraImageUploadedFrom": "صورة كاميرا جديدة تم رفعها من {0}",
"Channels": "القنوات",
"ChapterNameValue": "الباب {0}",
- "Collections": "المجاميع",
+ "Collections": "مجموعات",
"DeviceOfflineWithName": "تم قطع الاتصال بـ{0}",
"DeviceOnlineWithName": "{0} متصل",
"FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}",
- "Favorites": "المفضلات",
+ "Favorites": "التفضيلات",
"Folders": "المجلدات",
"Genres": "أنواع الأفلام",
- "HeaderAlbumArtists": "فنانو الألبومات",
- "HeaderCameraUploads": "Camera Uploads",
+ "HeaderAlbumArtists": "فناني الألبومات",
+ "HeaderCameraUploads": "تحميلات الكاميرا",
"HeaderContinueWatching": "استئناف المشاهدة",
"HeaderFavoriteAlbums": "الألبومات المفضلة",
"HeaderFavoriteArtists": "الفنانون المفضلون",
@@ -24,7 +24,7 @@
"HeaderFavoriteShows": "المسلسلات المفضلة",
"HeaderFavoriteSongs": "الأغاني المفضلة",
"HeaderLiveTV": "التلفاز المباشر",
- "HeaderNextUp": "التشغيل التالي",
+ "HeaderNextUp": "التالي",
"HeaderRecordingGroups": "مجموعات التسجيل",
"HomeVideos": "الفيديوهات المنزلية",
"Inherit": "توريث",
@@ -34,29 +34,29 @@
"LabelRunningTimeValue": "وقت التشغيل: {0}",
"Latest": "الأحدث",
"MessageApplicationUpdated": "لقد تم تحديث خادم أمبي",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
+ "MessageApplicationUpdatedTo": "تم تحديث سيرفر Jellyfin الى {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "تم تحديث إعدادات الخادم في قسم {0}",
"MessageServerConfigurationUpdated": "تم تحديث إعدادات الخادم",
"MixedContent": "محتوى مخلوط",
"Movies": "الأفلام",
"Music": "الموسيقى",
"MusicVideos": "الفيديوهات الموسيقية",
- "NameInstallFailed": "{0} installation failed",
+ "NameInstallFailed": "فشل التثبيت {0}",
"NameSeasonNumber": "الموسم {0}",
- "NameSeasonUnknown": "Season Unknown",
- "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+ "NameSeasonUnknown": "الموسم غير معروف",
+ "NewVersionIsAvailable": "نسخة حديثة من سيرفر Jellyfin متوفرة للتحميل .",
"NotificationOptionApplicationUpdateAvailable": "يوجد تحديث للتطبيق",
"NotificationOptionApplicationUpdateInstalled": "تم تحديث التطبيق",
"NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي",
"NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
"NotificationOptionCameraImageUploaded": "تم رقع صورة الكاميرا",
- "NotificationOptionInstallationFailed": "عملية التنصيب فشلت",
+ "NotificationOptionInstallationFailed": "فشل في التثبيت",
"NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
"NotificationOptionPluginError": "فشل في الملحق",
"NotificationOptionPluginInstalled": "تم تثبيت الملحق",
"NotificationOptionPluginUninstalled": "تمت إزالة الملحق",
- "NotificationOptionPluginUpdateInstalled": "تم تحديث الملحق",
- "NotificationOptionServerRestartRequired": "يجب إعادة تشغيل الخادم",
+ "NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق",
+ "NotificationOptionServerRestartRequired": "يجب إعادة تشغيل السيرفر",
"NotificationOptionTaskFailed": "فشل في المهمة المجدولة",
"NotificationOptionUserLockedOut": "تم إقفال حساب المستخدم",
"NotificationOptionVideoPlayback": "بدأ تشغيل الفيديو",
@@ -70,28 +70,28 @@
"ProviderValue": "المزود: {0}",
"ScheduledTaskFailedWithName": "العملية {0} فشلت",
"ScheduledTaskStartedWithName": "تم بدء {0}",
- "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
- "Shows": "Shows",
+ "ServerNameNeedsToBeRestarted": "يحتاج لإعادة تشغيله {0}",
+ "Shows": "الحلقات",
"Songs": "الأغاني",
- "StartupEmbyServerIsLoading": "خادم أمبي قيد التحميل. الرجاء المحاوية بعد حين",
+ "StartupEmbyServerIsLoading": "سيرفر Jellyfin قيد التشغيل . الرجاء المحاولة بعد قليل.",
"SubtitleDownloadFailureForItem": "عملية إنزال الترجمة فشلت لـ{0}",
- "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
- "SubtitlesDownloadedForItem": "تم إنزال الترجمات لـ {0}",
+ "SubtitleDownloadFailureFromForItem": "الترجمات فشلت في التحميل من {0} لـ {1}",
+ "SubtitlesDownloadedForItem": "تم تحميل الترجمات لـ {0}",
"Sync": "مزامنة",
"System": "النظام",
- "TvShows": "TV Shows",
+ "TvShows": "البرامج التلفزيونية",
"User": "المستخدم",
"UserCreatedWithName": "تم إنشاء المستخدم {0}",
"UserDeletedWithName": "تم حذف المستخدم {0}",
"UserDownloadingItemWithValues": "{0} يقوم بإنزال {1}",
"UserLockedOutWithName": "المستخدم {0} تم منعه من الدخول",
"UserOfflineFromDevice": "تم قطع اتصال {0} من {1}",
- "UserOnlineFromDevice": "{0} متصلة عبر {1}",
+ "UserOnlineFromDevice": "{0} متصل عبر {1}",
"UserPasswordChangedWithName": "تم تغيير كلمة السر للمستخدم {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
- "UserStartedPlayingItemWithValues": "قام {0} ببدء تشغيل {1}",
- "UserStoppedPlayingItemWithValues": "قام {0} بإيقاف تشغيل {1}",
- "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
- "ValueSpecialEpisodeName": "خاص - {0}",
+ "UserPolicyUpdatedWithName": "سياسة المستخدمين تم تحديثها لـ {0}",
+ "UserStartedPlayingItemWithValues": "قام {0} ببدء تشغيل {1} على {2}",
+ "UserStoppedPlayingItemWithValues": "قام {0} بإيقاف تشغيل {1} على {2}",
+ "ValueHasBeenAddedToLibrary": "{0} تم اضافتها الى مكتبة الوسائط",
+ "ValueSpecialEpisodeName": "مميز - {0}",
"VersionNumber": "الإصدار رقم {0}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index 003632968..99fda7aa6 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -15,7 +15,7 @@
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Genres": "Géneros",
- "HeaderAlbumArtists": "Artistas del Álbum",
+ "HeaderAlbumArtists": "Artistas del álbum",
"HeaderCameraUploads": "Subidos desde Camara",
"HeaderContinueWatching": "Continuar Viendo",
"HeaderFavoriteAlbums": "Álbumes favoritos",
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
new file mode 100644
index 000000000..15aa0a8ee
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -0,0 +1,48 @@
+{
+ "HeaderLiveTV": "Netti-TV",
+ "NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa",
+ "NameSeasonUnknown": "Tuntematon Kausi",
+ "NameSeasonNumber": "Kausi {0}",
+ "NameInstallFailed": "{0} asennus epäonnistui",
+ "MusicVideos": "Musiikkivideot",
+ "Music": "Musiikki",
+ "Movies": "Elokuvat",
+ "MixedContent": "Sekoitettu sisältö",
+ "MessageServerConfigurationUpdated": "Palvelimen konfiguraatio on päivitetty",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen konfiguraatio-osa {0} on päivitetty",
+ "MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty {0}",
+ "MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
+ "Latest": "Viimeisin",
+ "LabelRunningTimeValue": "Kesto: {0}",
+ "LabelIpAddressValue": "IP-osoite: {0}",
+ "ItemRemovedWithName": "{0} poistettiin kirjastosta",
+ "ItemAddedWithName": "{0} lisättiin kirjastoon",
+ "Inherit": "Periä",
+ "HomeVideos": "Kotivideot",
+ "HeaderRecordingGroups": "Äänitysryhmä",
+ "HeaderNextUp": "Seuraavaksi",
+ "HeaderFavoriteSongs": "Lempikappaleet",
+ "HeaderFavoriteShows": "Lempisarjat",
+ "HeaderFavoriteEpisodes": "Lempijaksot",
+ "HeaderCameraUploads": "Kamerasta Ladatut",
+ "HeaderFavoriteArtists": "Lempiartistit",
+ "HeaderFavoriteAlbums": "Lempialbumit",
+ "HeaderContinueWatching": "Jatka Katsomista",
+ "HeaderAlbumArtists": "Albumiartistit",
+ "Genres": "Genret",
+ "Folders": "Kansiot",
+ "Favorites": "Suosikit",
+ "FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys kohteesta {0}",
+ "DeviceOnlineWithName": "{0} on yhdistynyt",
+ "DeviceOfflineWithName": "{0} on katkaissut yhteytensä",
+ "Collections": "Kokoelmat",
+ "ChapterNameValue": "Luku: {0}",
+ "Channels": "Kanavat",
+ "CameraImageUploadedFrom": "Uusi kamerakuva on lähetetty kohteesta {0}",
+ "Books": "Kirjat",
+ "AuthenticationSucceededWithUserName": "{0} todennettu onnistuneesti",
+ "Artists": "Artistit",
+ "Application": "Sovellus",
+ "AppDeviceValues": "Sovellus: {0}, Laite: {1}",
+ "Albums": "Albumit"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json
index f2b7c408c..9bf4d2797 100644
--- a/Emby.Server.Implementations/Localization/Core/ko.json
+++ b/Emby.Server.Implementations/Localization/Core/ko.json
@@ -4,7 +4,7 @@
"Application": "애플리케이션",
"Artists": "아티스트",
"AuthenticationSucceededWithUserName": "{0} 인증에 성공했습니다.",
- "Books": "책",
+ "Books": "도서",
"CameraImageUploadedFrom": "새로운 카메라 이미지가 {0}에서 업로드되었습니다.",
"Channels": "채널",
"ChapterNameValue": "챕터 {0}",
@@ -83,8 +83,8 @@
"User": "사용자",
"UserCreatedWithName": "사용자 {0} 생성됨",
"UserDeletedWithName": "사용자 {0} 삭제됨",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
- "UserLockedOutWithName": "User {0} has been locked out",
+ "UserDownloadingItemWithValues": "{0}이(가) {1}을 다운로드 중입니다",
+ "UserLockedOutWithName": "유저 {0} 은(는) 잠금처리 되었습니다",
"UserOfflineFromDevice": "{0} has disconnected from {1}",
"UserOnlineFromDevice": "{0} is online from {1}",
"UserPasswordChangedWithName": "Password has been changed for user {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json
index 531dfe51f..c141a40f6 100644
--- a/Emby.Server.Implementations/Localization/Core/sl-SI.json
+++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json
@@ -3,7 +3,7 @@
"AppDeviceValues": "Aplikacija: {0}, Naprava: {1}",
"Application": "Aplikacija",
"Artists": "Izvajalci",
- "AuthenticationSucceededWithUserName": "{0} preverjanje uspešno",
+ "AuthenticationSucceededWithUserName": "{0} preverjanje pristnosti uspešno",
"Books": "Knjige",
"CameraImageUploadedFrom": "Nova fotografija je bila naložena z {0}",
"Channels": "Kanali",
@@ -44,13 +44,13 @@
"NameInstallFailed": "{0} namestitev neuspešna",
"NameSeasonNumber": "Sezona {0}",
"NameSeasonUnknown": "Season neznana",
- "NewVersionIsAvailable": "Nova razničica Jellyfin strežnika je na voljo za prenos.",
+ "NewVersionIsAvailable": "Nova različica Jellyfin strežnika je na voljo za prenos.",
"NotificationOptionApplicationUpdateAvailable": "Posodobitev aplikacije je na voljo",
"NotificationOptionApplicationUpdateInstalled": "Posodobitev aplikacije je bila nameščena",
"NotificationOptionAudioPlayback": "Predvajanje zvoka začeto",
"NotificationOptionAudioPlaybackStopped": "Predvajanje zvoka zaustavljeno",
"NotificationOptionCameraImageUploaded": "Posnetek kamere naložen",
- "NotificationOptionInstallationFailed": "Napaka pri nameščanju",
+ "NotificationOptionInstallationFailed": "Namestitev neuspešna",
"NotificationOptionNewLibraryContent": "Nove vsebine dodane",
"NotificationOptionPluginError": "Napaka dodatka",
"NotificationOptionPluginInstalled": "Dodatek nameščen",
@@ -92,6 +92,6 @@
"UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}",
"ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici",
- "ValueSpecialEpisodeName": "Special - {0}",
- "VersionNumber": "Version {0}"
+ "ValueSpecialEpisodeName": "Poseben - {0}",
+ "VersionNumber": "Različica {0}"
}
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 7947edeeb..0c0c77cda 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
@@ -457,13 +458,17 @@ namespace Emby.Server.Implementations.Updates
var hash = ToHexString(md5.ComputeHash(stream));
if (!string.Equals(package.checksum, hash, StringComparison.OrdinalIgnoreCase))
{
- _logger.LogDebug("{0}, {1}", package.checksum, hash);
- throw new InvalidDataException($"The checksums didn't match while installing {package.name}.");
+ _logger.LogError(
+ "The checksums didn't match while installing {Package}, expected: {Expected}, got: {Received}",
+ package.name,
+ package.checksum,
+ hash);
+ throw new InvalidDataException("The checksum of the received data doesn't match.");
}
if (Directory.Exists(targetDir))
{
- Directory.Delete(targetDir);
+ Directory.Delete(targetDir, true);
}
stream.Position = 0;
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index e9e884a3f..3ab19769a 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -84,6 +84,8 @@ namespace Jellyfin.Server
private static async Task StartApp(StartupOptions options)
{
+ var stopWatch = new Stopwatch();
+ stopWatch.Start();
ServerApplicationPaths appPaths = CreateApplicationPaths(options);
// $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
@@ -125,7 +127,9 @@ namespace Jellyfin.Server
Shutdown();
};
- _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version);
+ _logger.LogInformation(
+ "Jellyfin version: {Version}",
+ Assembly.GetEntryAssembly().GetName().Version.ToString(3));
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
@@ -166,6 +170,10 @@ namespace Jellyfin.Server
await appHost.RunStartupTasksAsync().ConfigureAwait(false);
+ stopWatch.Stop();
+
+ _logger.LogInformation("Startup complete {Time:g}", stopWatch.Elapsed);
+
// Block main thread until shutdown
await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index a223a4fe3..7dca7e814 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -610,9 +610,8 @@ namespace MediaBrowser.Api
process.Kill();
}
}
- catch (Exception ex)
+ catch (InvalidOperationException)
{
- Logger.LogError(ex, "Error killing transcoding job for {Path}", job.Path);
}
}
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 3a15c3776..b05e8c949 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -24,6 +25,7 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
using Microsoft.Net.Http.Headers;
+using static MediaBrowser.Common.HexHelper;
namespace MediaBrowser.Api.LiveTv
{
@@ -599,6 +601,7 @@ namespace MediaBrowser.Api.LiveTv
{
public bool ValidateLogin { get; set; }
public bool ValidateListings { get; set; }
+ public string Pw { get; set; }
}
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
@@ -866,10 +869,30 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Post(AddListingProvider request)
{
+ if (request.Pw != null)
+ {
+ request.Password = GetHashedString(request.Pw);
+ }
+
+ request.Pw = null;
+
var result = await _liveTvManager.SaveListingProvider(request, request.ValidateLogin, request.ValidateListings).ConfigureAwait(false);
return ToOptimizedResult(result);
}
+ /// <summary>
+ /// Gets the hashed string.
+ /// </summary>
+ private string GetHashedString(string str)
+ {
+ // SchedulesDirect requires a SHA1 hash of the user's password
+ // https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#obtain-a-token
+ using (SHA1 sha = SHA1.Create()) {
+ return ToHexString(
+ sha.ComputeHash(Encoding.UTF8.GetBytes(str)));
+ }
+ }
+
public void Delete(DeleteListingProvider request)
{
_liveTvManager.DeleteListingsProvider(request.Id);
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 369f63b13..c3dc6f7f2 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -2238,8 +2238,8 @@ namespace MediaBrowser.Controller.Entities
var currentCount = current.Length;
var newArr = new ItemImageInfo[currentCount + 1];
current.CopyTo(newArr, 0);
- current[currentCount] = image;
- ImageInfos = current;
+ newArr[currentCount] = image;
+ ImageInfos = newArr;
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index eb3d2ab81..991fc0b00 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -83,9 +83,6 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- // Avoid performing a second attempt when the first one
- // hasn't tried hardware encoding anyway.
- encodingOptions.EnableHardwareEncoding = false;
return defaultEncoder;
}
@@ -2548,7 +2545,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
- return "-hwaccel dxva2";
+ if(Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1))
+ return "-hwaccel d3d11va";
+ else
+ return "-hwaccel dxva2";
}
switch (videoStream.Codec.ToLowerInvariant())
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index b00350875..3620abfee 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -1,111 +1,157 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
+using System.Diagnostics;
using System.Linq;
+using System.Text;
using System.Text.RegularExpressions;
-using MediaBrowser.Model.Diagnostics;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.MediaEncoding.Encoder
{
public class EncoderValidator
{
- private readonly ILogger _logger;
- private readonly IProcessFactory _processFactory;
+ private const string DefaultEncoderPath = "ffmpeg";
- public EncoderValidator(ILogger logger, IProcessFactory processFactory)
+ private static readonly string[] requiredDecoders = new[]
{
- _logger = logger;
- _processFactory = processFactory;
- }
+ "mpeg2video",
+ "h264_qsv",
+ "hevc_qsv",
+ "mpeg2_qsv",
+ "vc1_qsv",
+ "h264_cuvid",
+ "hevc_cuvid",
+ "dts",
+ "ac3",
+ "aac",
+ "mp3",
+ "h264",
+ "hevc"
+ };
- public (IEnumerable<string> decoders, IEnumerable<string> encoders) GetAvailableCoders(string encoderPath)
+ private static readonly string[] requiredEncoders = new[]
+ {
+ "libx264",
+ "libx265",
+ "mpeg4",
+ "msmpeg4",
+ "libvpx",
+ "libvpx-vp9",
+ "aac",
+ "libmp3lame",
+ "libopus",
+ "libvorbis",
+ "srt",
+ "h264_nvenc",
+ "hevc_nvenc",
+ "h264_qsv",
+ "hevc_qsv",
+ "h264_omx",
+ "hevc_omx",
+ "h264_vaapi",
+ "hevc_vaapi",
+ "h264_v4l2m2m",
+ "ac3"
+ };
+
+ // Try and use the individual library versions to determine a FFmpeg version
+ // This lookup table is to be maintained with the following command line:
+ // $ ffmpeg -version | perl -ne ' print "$1=$2.$3," if /^(lib\w+)\s+(\d+)\.\s*(\d+)/'
+ private static readonly IReadOnlyDictionary<string, Version> _ffmpegVersionMap = new Dictionary<string, Version>
{
- _logger.LogInformation("Validating media encoder at {EncoderPath}", encoderPath);
+ { "libavutil=56.31,libavcodec=58.54,libavformat=58.29,libavdevice=58.8,libavfilter=7.57,libswscale=5.5,libswresample=3.5,libpostproc=55.5,", new Version(4, 2) },
+ { "libavutil=56.22,libavcodec=58.35,libavformat=58.20,libavdevice=58.5,libavfilter=7.40,libswscale=5.3,libswresample=3.3,libpostproc=55.3,", new Version(4, 1) },
+ { "libavutil=56.14,libavcodec=58.18,libavformat=58.12,libavdevice=58.3,libavfilter=7.16,libswscale=5.1,libswresample=3.1,libpostproc=55.1,", new Version(4, 0) },
+ { "libavutil=55.78,libavcodec=57.107,libavformat=57.83,libavdevice=57.10,libavfilter=6.107,libswscale=4.8,libswresample=2.9,libpostproc=54.7,", new Version(3, 4) },
+ { "libavutil=55.58,libavcodec=57.89,libavformat=57.71,libavdevice=57.6,libavfilter=6.82,libswscale=4.6,libswresample=2.7,libpostproc=54.5,", new Version(3, 3) },
+ { "libavutil=55.34,libavcodec=57.64,libavformat=57.56,libavdevice=57.1,libavfilter=6.65,libswscale=4.2,libswresample=2.3,libpostproc=54.1,", new Version(3, 2) },
+ { "libavutil=54.31,libavcodec=56.60,libavformat=56.40,libavdevice=56.4,libavfilter=5.40,libswscale=3.1,libswresample=1.2,libpostproc=53.3,", new Version(2, 8) }
+ };
- var decoders = GetCodecs(encoderPath, Codec.Decoder);
- var encoders = GetCodecs(encoderPath, Codec.Encoder);
+ private readonly ILogger _logger;
- _logger.LogInformation("Encoder validation complete");
+ private readonly string _encoderPath;
- return (decoders, encoders);
+ public EncoderValidator(ILogger logger, string encoderPath = DefaultEncoderPath)
+ {
+ _logger = logger;
+ _encoderPath = encoderPath;
}
- public bool ValidateVersion(string encoderAppPath, bool logOutput)
+ public static Version MinVersion { get; } = new Version(4, 0);
+
+ public static Version MaxVersion { get; } = null;
+
+ public bool ValidateVersion()
{
string output = null;
try
{
- output = GetProcessOutput(encoderAppPath, "-version");
+ output = GetProcessOutput(_encoderPath, "-version");
}
catch (Exception ex)
{
- if (logOutput)
- {
- _logger.LogError(ex, "Error validating encoder");
- }
+ _logger.LogError(ex, "Error validating encoder");
}
if (string.IsNullOrWhiteSpace(output))
{
- if (logOutput)
- {
- _logger.LogError("FFmpeg validation: The process returned no result");
- }
+ _logger.LogError("FFmpeg validation: The process returned no result");
return false;
}
_logger.LogDebug("ffmpeg output: {Output}", output);
- if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
+ return ValidateVersionInternal(output);
+ }
+
+ internal bool ValidateVersionInternal(string versionOutput)
+ {
+ if (versionOutput.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
{
- if (logOutput)
- {
- _logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported");
- }
+ _logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported");
return false;
}
- // The min and max FFmpeg versions required to run jellyfin successfully
- var minRequired = new Version(4, 0);
- var maxRequired = new Version(4, 0);
-
// Work out what the version under test is
- var underTest = GetFFmpegVersion(output);
+ var version = GetFFmpegVersion(versionOutput);
- if (logOutput)
- {
- _logger.LogInformation("FFmpeg validation: Found ffmpeg version {0}", underTest != null ? underTest.ToString() : "unknown");
+ _logger.LogInformation("Found ffmpeg version {0}", version != null ? version.ToString() : "unknown");
- if (underTest == null) // Version is unknown
+ if (version == null)
+ {
+ if (MinVersion != null && MaxVersion != null) // Version is unknown
{
- if (minRequired.Equals(maxRequired))
+ if (MinVersion == MaxVersion)
{
- _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", minRequired.ToString());
+ _logger.LogWarning("FFmpeg validation: We recommend ffmpeg version {0}", MinVersion);
}
else
{
- _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", minRequired.ToString(), maxRequired.ToString());
+ _logger.LogWarning("FFmpeg validation: We recommend a minimum of {0} and maximum of {1}", MinVersion, MaxVersion);
}
}
- else if (underTest.CompareTo(minRequired) < 0) // Version is below what we recommend
- {
- _logger.LogWarning("FFmpeg validation: The minimum recommended ffmpeg version is {0}", minRequired.ToString());
- }
- else if (underTest.CompareTo(maxRequired) > 0) // Version is above what we recommend
- {
- _logger.LogWarning("FFmpeg validation: The maximum recommended ffmpeg version is {0}", maxRequired.ToString());
- }
- else // Version is ok
- {
- _logger.LogInformation("FFmpeg validation: Found suitable ffmpeg version");
- }
+
+ return false;
+ }
+ else if (MinVersion != null && version < MinVersion) // Version is below what we recommend
+ {
+ _logger.LogWarning("FFmpeg validation: The minimum recommended ffmpeg version is {0}", MinVersion);
+ return false;
+ }
+ else if (MaxVersion != null && version > MaxVersion) // Version is above what we recommend
+ {
+ _logger.LogWarning("FFmpeg validation: The maximum recommended ffmpeg version is {0}", MaxVersion);
+ return false;
}
- // underTest shall be null if versions is unknown
- return (underTest == null) ? false : (underTest.CompareTo(minRequired) >= 0 && underTest.CompareTo(maxRequired) <= 0);
+ return true;
}
+ public IEnumerable<string> GetDecoders() => GetCodecs(Codec.Decoder);
+
+ public IEnumerable<string> GetEncoders() => GetCodecs(Codec.Encoder);
+
/// <summary>
/// Using the output from "ffmpeg -version" work out the FFmpeg version.
/// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy
@@ -115,10 +161,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
/// <param name="output"></param>
/// <returns></returns>
- static private Version GetFFmpegVersion(string output)
+ internal static Version GetFFmpegVersion(string output)
{
// For pre-built binaries the FFmpeg version should be mentioned at the very start of the output
- var match = Regex.Match(output, @"ffmpeg version (\d+\.\d+)");
+ var match = Regex.Match(output, @"^ffmpeg version n?((?:\d+\.?)+)");
if (match.Success)
{
@@ -126,25 +172,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
else
{
- // Try and use the individual library versions to determine a FFmpeg version
- // This lookup table is to be maintained with the following command line:
- // $ ./ffmpeg.exe -version | perl -ne ' print "$1=$2.$3," if /^(lib\w+)\s+(\d+)\.\s*(\d+)/'
- var lut = new ReadOnlyDictionary<Version, string>
- (new Dictionary<Version, string>
- {
- { new Version("4.1"), "libavutil=56.22,libavcodec=58.35,libavformat=58.20,libavdevice=58.5,libavfilter=7.40,libswscale=5.3,libswresample=3.3,libpostproc=55.3," },
- { new Version("4.0"), "libavutil=56.14,libavcodec=58.18,libavformat=58.12,libavdevice=58.3,libavfilter=7.16,libswscale=5.1,libswresample=3.1,libpostproc=55.1," },
- { new Version("3.4"), "libavutil=55.78,libavcodec=57.107,libavformat=57.83,libavdevice=57.10,libavfilter=6.107,libswscale=4.8,libswresample=2.9,libpostproc=54.7," },
- { new Version("3.3"), "libavutil=55.58,libavcodec=57.89,libavformat=57.71,libavdevice=57.6,libavfilter=6.82,libswscale=4.6,libswresample=2.7,libpostproc=54.5," },
- { new Version("3.2"), "libavutil=55.34,libavcodec=57.64,libavformat=57.56,libavdevice=57.1,libavfilter=6.65,libswscale=4.2,libswresample=2.3,libpostproc=54.1," },
- { new Version("2.8"), "libavutil=54.31,libavcodec=56.60,libavformat=56.40,libavdevice=56.4,libavfilter=5.40,libswscale=3.1,libswresample=1.2,libpostproc=53.3," }
- });
-
// Create a reduced version string and lookup key from dictionary
- var reducedVersion = GetVersionString(output);
+ var reducedVersion = GetLibrariesVersionString(output);
// Try to lookup the string and return Key, otherwise if not found returns null
- return lut.FirstOrDefault(x => x.Value == reducedVersion).Key;
+ return _ffmpegVersionMap.TryGetValue(reducedVersion, out Version version) ? version : null;
}
}
@@ -154,76 +186,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
/// <param name="output"></param>
/// <returns></returns>
- static private string GetVersionString(string output)
+ private static string GetLibrariesVersionString(string output)
{
- string pattern = @"((?<name>lib\w+)\s+(?<major>\d+)\.\s*(?<minor>\d+))";
- RegexOptions options = RegexOptions.Multiline;
-
- string rc = null;
-
- foreach (Match m in Regex.Matches(output, pattern, options))
+ var rc = new StringBuilder(144);
+ foreach (Match m in Regex.Matches(
+ output,
+ @"((?<name>lib\w+)\s+(?<major>\d+)\.\s*(?<minor>\d+))",
+ RegexOptions.Multiline))
{
- rc += string.Concat(m.Groups["name"], '=', m.Groups["major"], '.', m.Groups["minor"], ',');
+ rc.Append(m.Groups["name"])
+ .Append('=')
+ .Append(m.Groups["major"])
+ .Append('.')
+ .Append(m.Groups["minor"])
+ .Append(',');
}
- return rc;
+ return rc.Length == 0 ? null : rc.ToString();
}
- private static readonly string[] requiredDecoders = new[]
- {
- "mpeg2video",
- "h264_qsv",
- "hevc_qsv",
- "mpeg2_qsv",
- "vc1_qsv",
- "h264_cuvid",
- "hevc_cuvid",
- "dts",
- "ac3",
- "aac",
- "mp3",
- "h264",
- "hevc"
- };
-
- private static readonly string[] requiredEncoders = new[]
- {
- "libx264",
- "libx265",
- "mpeg4",
- "msmpeg4",
- "libvpx",
- "libvpx-vp9",
- "aac",
- "libmp3lame",
- "libopus",
- "libvorbis",
- "srt",
- "h264_nvenc",
- "hevc_nvenc",
- "h264_qsv",
- "hevc_qsv",
- "h264_omx",
- "hevc_omx",
- "h264_vaapi",
- "hevc_vaapi",
- "h264_v4l2m2m",
- "ac3"
- };
-
private enum Codec
{
Encoder,
Decoder
}
- private IEnumerable<string> GetCodecs(string encoderAppPath, Codec codec)
+ private IEnumerable<string> GetCodecs(Codec codec)
{
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
string output = null;
try
{
- output = GetProcessOutput(encoderAppPath, "-" + codecstr);
+ output = GetProcessOutput(_encoderPath, "-" + codecstr);
}
catch (Exception ex)
{
@@ -250,45 +244,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetProcessOutput(string path, string arguments)
{
- IProcess process = _processFactory.Create(new ProcessOptions
+ using (var process = new Process()
{
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = path,
- Arguments = arguments,
- IsHidden = true,
- ErrorDialog = false,
- RedirectStandardOutput = true,
- // ffmpeg uses stderr to log info, don't show this
- RedirectStandardError = true
- });
-
- _logger.LogDebug("Running {Path} {Arguments}", path, arguments);
-
- using (process)
- {
- process.Start();
-
- try
+ StartInfo = new ProcessStartInfo(path, arguments)
{
- return process.StandardOutput.ReadToEnd();
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ WindowStyle = ProcessWindowStyle.Hidden,
+ ErrorDialog = false,
+ RedirectStandardOutput = true,
+ // ffmpeg uses stderr to log info, don't show this
+ RedirectStandardError = true
}
- catch
- {
- _logger.LogWarning("Killing process {Path} {Arguments}", path, arguments);
+ })
+ {
+ _logger.LogDebug("Running {Path} {Arguments}", path, arguments);
- // Hate having to do this
- try
- {
- process.Kill();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error killing process");
- }
+ process.Start();
- throw;
- }
+ return process.StandardOutput.ReadToEnd();
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 75bb960c3..04ff66991 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -114,13 +114,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
FFprobePath = Regex.Replace(FFmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1");
// Interrogate to understand what coders are supported
- var result = new EncoderValidator(_logger, _processFactory).GetAvailableCoders(FFmpegPath);
+ var validator = new EncoderValidator(_logger, FFmpegPath);
- SetAvailableDecoders(result.decoders);
- SetAvailableEncoders(result.encoders);
+ SetAvailableDecoders(validator.GetDecoders());
+ SetAvailableEncoders(validator.GetEncoders());
}
- _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation.ToString(), FFmpegPath ?? string.Empty);
+ _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation, FFmpegPath ?? string.Empty);
}
/// <summary>
@@ -183,11 +183,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
if (File.Exists(path))
{
- rc = new EncoderValidator(_logger, _processFactory).ValidateVersion(path, true);
+ rc = new EncoderValidator(_logger, path).ValidateVersion();
if (!rc)
{
- _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location.ToString(), path);
+ _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location, path);
}
// ToDo - Enable the ffmpeg validator. At the moment any version can be used.
@@ -198,7 +198,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
else
{
- _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location.ToString(), path);
+ _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location, path);
}
}
@@ -228,9 +228,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
- private string ExistsOnSystemPath(string filename)
+ private string ExistsOnSystemPath(string fileName)
{
- string inJellyfinPath = GetEncoderPathFromDirectory(System.AppContext.BaseDirectory, filename);
+ string inJellyfinPath = GetEncoderPathFromDirectory(System.AppContext.BaseDirectory, fileName);
if (!string.IsNullOrEmpty(inJellyfinPath))
{
return inJellyfinPath;
@@ -239,13 +239,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
foreach (var path in values.Split(Path.PathSeparator))
{
- var candidatePath = GetEncoderPathFromDirectory(path, filename);
+ var candidatePath = GetEncoderPathFromDirectory(path, fileName);
if (!string.IsNullOrEmpty(candidatePath))
{
return candidatePath;
}
}
+
return null;
}
diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
index a9491374b..7b74cfc89 100644
--- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
+++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
@@ -1,5 +1,6 @@
using System.Reflection;
using System.Resources;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
+[assembly: InternalsVisibleTo("Jellyfin.MediaEncoding.Tests")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index d64ea35eb..24e771403 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -162,7 +162,6 @@ namespace MediaBrowser.Model.Configuration
public bool SkipDeserializationForBasicTypes { get; set; }
public string ServerName { get; set; }
- public string WanDdns { get; set; }
public string BaseUrl { get; set; }
public string UICulture { get; set; }
diff --git a/MediaBrowser.Model/System/PublicSystemInfo.cs b/MediaBrowser.Model/System/PublicSystemInfo.cs
index d6e031e42..23f6d378c 100644
--- a/MediaBrowser.Model/System/PublicSystemInfo.cs
+++ b/MediaBrowser.Model/System/PublicSystemInfo.cs
@@ -9,12 +9,6 @@ namespace MediaBrowser.Model.System
public string LocalAddress { get; set; }
/// <summary>
- /// Gets or sets the wan address.
- /// </summary>
- /// <value>The wan address.</value>
- public string WanAddress { get; set; }
-
- /// <summary>
/// Gets or sets the name of the server.
/// </summary>
/// <value>The name of the server.</value>
@@ -25,7 +19,7 @@ namespace MediaBrowser.Model.System
/// </summary>
/// <value>The version.</value>
public string Version { get; set; }
-
+
/// <summary>
/// The product name. This is the AssemblyProduct name.
/// </summary>
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index d23ca1cdb..dd4e9f8a6 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -57,6 +57,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FBBB5129
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Common.Tests", "tests\Jellyfin.Common.Tests\Jellyfin.Common.Tests.csproj", "{DF194677-DFD3-42AF-9F75-D44D5A416478}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -159,6 +161,10 @@ Global
{DF194677-DFD3-42AF-9F75-D44D5A416478}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF194677-DFD3-42AF-9F75-D44D5A416478}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF194677-DFD3-42AF-9F75-D44D5A416478}.Release|Any CPU.Build.0 = Release|Any CPU
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -186,5 +192,6 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index 584260d24..b9958364b 100644
--- a/README.md
+++ b/README.md
@@ -23,17 +23,17 @@
Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media. It is an alternative to the proprietary Emby and Plex, to provide media from a dedicated server to end-user devices via multiple apps. Jellyfin is descended from Emby's 3.5.2 release and ported to the .NET Core framework to enable full cross-platform support. There are no strings attached, no premium licenses or features, and no hidden agendas: just a team who want to build something better and work together to achieve it. We welcome anyone who is interested in joining us in our quest!
-For further details, please see [our documentation page](https://jellyfin.readthedocs.io). To receive the latest updates, get help with Jellyfin, and join the community, please visit [one of our communication channels on Matrix/Riot or social media](https://jellyfin.readthedocs.io/en/latest/getting-help/).
+For further details, please see [our documentation page](https://docs.jellyfin.org/). To receive the latest updates, get help with Jellyfin, and join the community, please visit [one of our communication channels on Matrix/Riot or social media](https://docs.jellyfin.org/general/getting-help.html).
-For more information about the project, please see our [about page](https://jellyfin.readthedocs.io/en/latest/about/).
+For more information about the project, please see our [about page](https://docs.jellyfin.org/general/about.html).
<p align="center">
<strong>Want to get started?</strong>
-<em>Choose from <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/installing/">Prebuilt Packages</a> or <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/building/">Build from Source</a>, then see our <a href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/quick-start/">quick start guide</a>.</em>
+<em>Choose from <a href="https://docs.jellyfin.org/general/administration/installing.html">Prebuilt Packages</a> or <a href="https://docs.jellyfin.org/general/administration/building.html">Build from Source</a>, then see our <a href="https://docs.jellyfin.org/general/administration/quick-start.html">quick start guide</a>.</em>
</p>
<p align="center">
<strong>Want to contribute?</strong>
-<em>Check out <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/contributing/">our documentation for guidelines</a>.</em>
+<em>Check out <a href="https://docs.jellyfin.org/general/contributing/index.html">our documentation for guidelines</a>.</em>
</p>
<p align="center">
<strong>New idea or improvement?</strong>
@@ -41,5 +41,5 @@ For more information about the project, please see our [about page](https://jell
</p>
<p align="center">
<strong>Something not working right?</strong>
-<em>Open an <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/issues/">Issue</a>.</em>
+<em>Open an <a href="https://docs.jellyfin.org/general/contributing/issues.html">Issue</a>.</em>
</p>
diff --git a/build b/build
index fb4ff1984..95d5d5c49 100755
--- a/build
+++ b/build
@@ -164,40 +164,6 @@ for target_platform in ${platform[@]}; do
fi
done
-if [[ ${web_branch} != 'local' ]]; then
- # Initialize submodules
- git submodule update --init --recursive
-
- # configure branch
- pushd MediaBrowser.WebDashboard/jellyfin-web
-
- if ! git diff-index --quiet HEAD --; then
- popd
- echo
- echo "ERROR: Your 'jellyfin-web' submodule working directory is not clean!"
- echo "This script will overwrite your unstaged and unpushed changes."
- echo "Please do development on 'jellyfin-web' outside of the submodule."
- exit 1
- fi
-
- git fetch --all
- # If this is an official branch name, fetch it from origin
- official_branches_regex="^master$|^dev$|^release-.*$|^hotfix-.*$"
- if [[ ${web_branch} =~ ${official_branches_regex} ]]; then
- git checkout origin/${web_branch} || {
- echo "ERROR: 'jellyfin-web' branch 'origin/${web_branch}' is invalid."
- exit 1
- }
- # Otherwise, just check out the local branch (for testing, etc.)
- else
- git checkout ${web_branch} || {
- echo "ERROR: 'jellyfin-web' branch '${web_branch}' is invalid."
- exit 1
- }
- fi
- popd
-fi
-
# Execute each platform and action in order, if said action is enabled
pushd deployment/
for target_platform in ${platform[@]}; do
@@ -214,7 +180,7 @@ for target_platform in ${platform[@]}; do
for target_action in ${action[@]}; do
echo -e ">> Processing action ${target_action}"
if [[ -f ${target_action}.sh && -x ${target_action}.sh ]]; then
- ./${target_action}.sh
+ ./${target_action}.sh web_branch=${web_branch}
fi
done
if [[ -d pkg-dist/ ]]; then
diff --git a/bump_version b/bump_version
index 590020864..106dd7a78 100755
--- a/bump_version
+++ b/bump_version
@@ -24,33 +24,6 @@ fi
shared_version_file="./SharedVersion.cs"
build_file="./build.yaml"
-if [[ -z $2 ]]; then
- web_branch="$( git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/' )"
-else
- web_branch="$2"
-fi
-
-# Initialize submodules
-git submodule update --init --recursive
-
-# configure branch
-pushd MediaBrowser.WebDashboard/jellyfin-web
-
-if ! git diff-index --quiet HEAD --; then
- popd
- echo
- echo "ERROR: Your 'jellyfin-web' submodule working directory is not clean!"
- echo "This script will overwrite your unstaged and unpushed changes."
- echo "Please do development on 'jellyfin-web' outside of the submodule."
- exit 1
-fi
-
-git fetch --all
-git checkout origin/${web_branch}
-popd
-
-git add MediaBrowser.WebDashboard/jellyfin-web
-
new_version="$1"
# Parse the version from the AssemblyVersion
diff --git a/deployment/README.md b/deployment/README.md
index a00cd3e6c..a805f59ca 100644
--- a/deployment/README.md
+++ b/deployment/README.md
@@ -11,10 +11,8 @@ This directory contains the packaging configuration of Jellyfin for multiple pla
### Portable Builds (archives)
-* `debian-x64`: Portable binary archive for Debian amd64 systems.
-* `ubuntu-x64`: Portable binary archive for Ubuntu amd64 systems.
* `linux-x64`: Portable binary archive for generic Linux amd64 systems.
-* `osx-x64`: Portable binary archive for MacOS amd64 systems.
+* `macos`: Portable binary archive for MacOS amd64 systems.
* `win-x64`: Portable binary archive for Windows amd64 systems.
* `win-x86`: Portable binary archive for Windows i386 systems.
@@ -22,10 +20,10 @@ This directory contains the packaging configuration of Jellyfin for multiple pla
These builds are not necessarily run from the `build` script, but are present for other platforms.
-* `framework`: Compiled `.dll` for use with .NET Core runtime on any system.
+* `portable`: Compiled `.dll` for use with .NET Core runtime on any system.
* `docker`: Docker manifests for auto-publishing.
* `unraid`: unRaid Docker template; not built by `build` but imported into unRaid directly.
-* `win-generic`: Portable binary for generic Windows systems.
+* `windows`: Support files and scripts for Windows CI build.
## Package Specification
@@ -62,52 +60,3 @@ These builds are not necessarily run from the `build` script, but are present fo
* Upon completion of the defined actions, at least one output file must be created in the `<platform>/pkg-dist` directory.
* Output files will be moved to the directory `jellyfin-build/<platform>` one directory above the repository root upon completion.
-
-### Common Functions
-
-* A number of common functions are defined in `deployment/common.build.sh` for use by platform scripts.
-
-* Each action script should import the common functions to define a number of standard variables.
-
-* The common variables are:
-
- * `ROOT`: The Jellyfin repostiory root, usually `../..`.
- * `CONFIG`: The .NET config, usually `Release`.
- * `DOTNETRUNTIME`: The .NET `--runtime` value, platform-dependent.
- * `OUTPUT_DIR`: The intermediate output dir, usually `./dist/jellyfin_${VERSION}`.
- * `BUILD_CONTEXT`: The Docker build context, usually `../..`.
- * `DOCKERFILE`: The Dockerfile, usually `Dockerfile` in the platform directory.
- * `IMAGE_TAG`: A tag for the built Docker image.
- * `PKG_DIR`: The final binary output directory for collection, invariably `pkg-dist`.
- * `ARCHIVE_CMD`: The compression/archive command for release archives, usually `tar -xvzf` or `zip`.
-
-#### `get_version`
-
-Reads the version information from `SharedVersion.cs`.
-
-**Arguments:** `ROOT`
-
-#### `build_jellyfin`
-
-Build a standard self-contained binary in the current OS context.
-
-**Arguments:** `ROOT` `CONFIG` `DOTNETRUNTIME` `OUTPUT_DIR`
-
-#### `build_jellyfin_docker`
-
-Build a standard self-contained binary in a Docker image.
-
-**Arguments:** `BUILD_CONTEXT` `DOCKERFILE` `IMAGE_TAG`
-
-#### `clean_jellyfin`
-
-Clean up a build for housekeeping.
-
-**Arguments:** `ROOT` `CONFIG` `OUTPUT_DIR` `PKG_DIR`
-
-#### `package_portable`
-
-Produce a compressed archive.
-
-**Arguments:** `ROOT` `OUTPUT_DIR` `PKG_DIR` `ARCHIVE_CMD`
-
diff --git a/deployment/centos-package-x64/Dockerfile b/deployment/centos-package-x64/Dockerfile
index 38853f173..99f538bc2 100644
--- a/deployment/centos-package-x64/Dockerfile
+++ b/deployment/centos-package-x64/Dockerfile
@@ -8,13 +8,24 @@ ARG SDK_VERSION=2.2
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
-# Prepare CentOS build environment
+# Prepare CentOS environment
RUN yum update -y \
- && yum install -y @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel \
- && rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm \
+ && yum install -y epel-release
+
+# Install build dependencies
+RUN yum install -y @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel nodejs wget git
+
+# Install DotNET SDK
+RUN rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm \
&& rpmdev-setuptree \
- && yum install -y dotnet-sdk-${SDK_VERSION} \
- && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && yum install -y dotnet-sdk-${SDK_VERSION}
+
+# Install yarn package manager
+RUN wget -q -O /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \
+ && yum install -y yarn
+
+# Create symlinks and directories
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
&& mkdir -p ${SOURCE_DIR}/SPECS \
&& ln -s ${PLATFORM_DIR}/pkg-src/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \
&& mkdir -p ${SOURCE_DIR}/SOURCES \
diff --git a/deployment/centos-package-x64/clean.sh b/deployment/centos-package-x64/clean.sh
index 7278372e1..31455de0d 100755
--- a/deployment/centos-package-x64/clean.sh
+++ b/deployment/centos-package-x64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/centos-package-x64/docker-build.sh b/deployment/centos-package-x64/docker-build.sh
index cefb1652e..014f582f0 100755
--- a/deployment/centos-package-x64/docker-build.sh
+++ b/deployment/centos-package-x64/docker-build.sh
@@ -8,7 +8,69 @@ set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
-ls -al SOURCES/pkg-src/
+VERSION="$( grep '^Version:' ${SOURCE_DIR}/SOURCES/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Create RPM source archive
+GNU_TAR=1
+echo "Bundling all sources for RPM build."
+tar \
+--transform "s,^\.,jellyfin-${VERSION}," \
+--exclude='.git*' \
+--exclude='**/.git' \
+--exclude='**/.hg' \
+--exclude='**/.vs' \
+--exclude='**/.vscode' \
+--exclude='deployment' \
+--exclude='**/bin' \
+--exclude='**/obj' \
+--exclude='**/.nuget' \
+--exclude='*.deb' \
+--exclude='*.rpm' \
+-czf "${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-${VERSION}.tar.gz" \
+-C ${SOURCE_DIR} ./ || GNU_TAR=0
+
+if [ $GNU_TAR -eq 0 ]; then
+ echo "The installed tar binary did not support --transform. Using workaround."
+ package_temporary_dir="$( mktemp -d )"
+ mkdir -p "${package_temporary_dir}/jellyfin"
+ # Not GNU tar
+ tar \
+ --exclude='.git*' \
+ --exclude='**/.git' \
+ --exclude='**/.hg' \
+ --exclude='**/.vs' \
+ --exclude='**/.vscode' \
+ --exclude='deployment' \
+ --exclude='**/bin' \
+ --exclude='**/obj' \
+ --exclude='**/.nuget' \
+ --exclude='*.deb' \
+ --exclude='*.rpm' \
+ -czf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
+ -C ${SOURCE_DIR} ./
+ echo "Extracting filtered package."
+ mkdir -p "${package_temporary_dir}/jellyfin-${VERSION}"
+ tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
+ echo "Removing filtered package."
+ rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
+ echo "Repackaging package into final tarball."
+ tar -czf "${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
+ rm -rf ${package_temporary_dir}
+fi
# Build RPM
spectool -g -R SPECS/jellyfin.spec
diff --git a/deployment/centos-package-x64/package.sh b/deployment/centos-package-x64/package.sh
index df5a66580..1b983f49d 100755
--- a/deployment/centos-package-x64/package.sh
+++ b/deployment/centos-package-x64/package.sh
@@ -1,13 +1,15 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
WORKDIR="$( pwd )"
-VERSION="$( grep '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
-pkg_src_dir="${WORKDIR}/pkg-src"
current_user="$( whoami )"
image_name="jellyfin-centos-build"
@@ -21,57 +23,12 @@ else
docker_sudo=""
fi
-# Create RPM source archive
-GNU_TAR=1
+# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
-echo "Bundling all sources for RPM build."
-tar \
---transform "s,^\.,jellyfin-${VERSION}," \
---exclude='.git*' \
---exclude='**/.git' \
---exclude='**/.hg' \
---exclude='**/.vs' \
---exclude='**/.vscode' \
---exclude='deployment' \
---exclude='**/bin' \
---exclude='**/obj' \
---exclude='**/.nuget' \
---exclude='*.deb' \
---exclude='*.rpm' \
--czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" \
--C "../.." ./ || GNU_TAR=0
-
-if [ $GNU_TAR -eq 0 ]; then
- echo "The installed tar binary did not support --transform. Using workaround."
- mkdir -p "${package_temporary_dir}/jellyfin"
- # Not GNU tar
- tar \
- --exclude='.git*' \
- --exclude='**/.git' \
- --exclude='**/.hg' \
- --exclude='**/.vs' \
- --exclude='**/.vscode' \
- --exclude='deployment' \
- --exclude='**/bin' \
- --exclude='**/obj' \
- --exclude='**/.nuget' \
- --exclude='*.deb' \
- --exclude='*.rpm' \
- -zcf \
- "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
- -C "../.." ./
- echo "Extracting filtered package."
- tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
- echo "Removing filtered package."
- rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
- echo "Repackaging package into final tarball."
- tar -czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
-fi
-
# 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# Move the RPMs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/rpm/* "${output_dir}"
diff --git a/deployment/common.build.sh b/deployment/common.build.sh
deleted file mode 100755
index 000872ea9..000000000
--- a/deployment/common.build.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env bash
-
-set -o errexit
-set -o nounset
-
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-CYAN='\033[0;36m'
-NC='\033[0m' # No Color
-
-DEFAULT_BUILD_CONTEXT="../.."
-DEFAULT_ROOT="."
-DEFAULT_DOTNETRUNTIME="framework"
-DEFAULT_CONFIG="Release"
-DEFAULT_OUTPUT_DIR="dist/jellyfin-git"
-DEFAULT_PKG_DIR="pkg-dist"
-DEFAULT_DOCKERFILE="Dockerfile"
-DEFAULT_ARCHIVE_CMD="tar -xvzf"
-
-# Parse the version from the build.yaml version
-get_version()
-(
- local ROOT=${1-$DEFAULT_ROOT}
- grep "version:" ${ROOT}/build.yaml \
- | sed -E 's/version: "([0-9\.]+.*)"/\1/'
-)
-
-# Run a build
-build_jellyfin()
-(
- ROOT=${1-$DEFAULT_ROOT}
- CONFIG=${2-$DEFAULT_CONFIG}
- DOTNETRUNTIME=${3-$DEFAULT_DOTNETRUNTIME}
- OUTPUT_DIR=${4-$DEFAULT_OUTPUT_DIR}
-
- echo -e "${CYAN}Building jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}'.${NC}"
- if [[ $DOTNETRUNTIME == 'framework' ]]; then
- dotnet publish "${ROOT}" --configuration "${CONFIG}" --output="${OUTPUT_DIR}" "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
- else
- dotnet publish "${ROOT}" --configuration "${CONFIG}" --output="${OUTPUT_DIR}" --self-contained --runtime ${DOTNETRUNTIME} "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
- fi
- EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Build jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Build jellyfin in '${ROOT}' for ${DOTNETRUNTIME} with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' FAILED.${NC}"
- fi
-)
-
-# Run a docker
-build_jellyfin_docker()
-(
- BUILD_CONTEXT=${1-$DEFAULT_BUILD_CONTEXT}
- DOCKERFILE=${2-$DEFAULT_DOCKERFILE}
- IMAGE_TAG=${3-"jellyfin:$(git rev-parse --abbrev-ref HEAD)"}
-
- echo -e "${CYAN}Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}'.${NC}"
- docker build -t ${IMAGE_TAG} -f ${DOCKERFILE} ${BUILD_CONTEXT}
- EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Building jellyfin docker image in '${BUILD_CONTEXT}' with Dockerfile '${DOCKERFILE}' and tag '${IMAGE_TAG}' FAILED.${NC}"
- fi
-)
-
-# Clean a build
-clean_jellyfin()
-(
- local ROOT=${1-$DEFAULT_ROOT}
- local CONFIG=${2-$DEFAULT_CONFIG}
- local OUTPUT_DIR=${3-$DEFAULT_OUTPUT_DIR}
- local PKG_DIR=${4-$DEFAULT_PKG_DIR}
- echo -e "${CYAN}Cleaning jellyfin in '${ROOT}'' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}'.${NC}"
- echo -e "${CYAN}Deleting '${OUTPUT_DIR}'${NC}"
- rm -rf "$OUTPUT_DIR"
- echo -e "${CYAN}Deleting '${PKG_DIR}'${NC}"
- rm -rf "$PKG_DIR"
- dotnet clean "${ROOT}" -maxcpucount:1 --configuration ${CONFIG}
- local EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Clean jellyfin in '${ROOT}' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Clean jellyfin in '${ROOT}' with configuration ${CONFIG} and output directory '${OUTPUT_DIR}' failed.${NC}"
- fi
-)
-
-# Packages the output folder into an archive.
-package_portable()
-(
- local ROOT=${1-$DEFAULT_ROOT}
- local OUTPUT_DIR=${2-$DEFAULT_OUTPUT_DIR}
- local PKG_DIR=${3-$DEFAULT_PKG_DIR}
- local ARCHIVE_CMD=${4-$DEFAULT_ARCHIVE_CMD}
- # Package portable build result
- if [ -d ${OUTPUT_DIR} ]; then
- echo -e "${CYAN}Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}'.${NC}"
- mkdir -p ${PKG_DIR}
- tar -zcvf "${PKG_DIR}/`basename "${OUTPUT_DIR}"`.portable.tar.gz" -C "`dirname "${OUTPUT_DIR}"`" "`basename "${OUTPUT_DIR}"`"
- local EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' FAILED.${NC}"
- fi
- else
- echo -e "${RED}[FAIL] Build artifacts do not exist for ${OUTPUT_DIR}. Run build.sh first.${NC}"
- fi
-)
-
diff --git a/deployment/debian-package-arm64/Dockerfile.amd64 b/deployment/debian-package-arm64/Dockerfile.amd64
index a05581d71..5644c1470 100644
--- a/deployment/debian-package-arm64/Dockerfile.amd64
+++ b/deployment/debian-package-arm64/Dockerfile.amd64
@@ -29,6 +29,12 @@ RUN dpkg --add-architecture arm64 \
&& cd cross-gcc-packages-amd64/cross-gcc-8-arm64 \
&& apt-get install -y gcc-8-source libstdc++-8-dev-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase 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 libssl-dev:arm64 liblttng-ust0:arm64 libstdc++-8-dev:arm64
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/debian-package-arm64/clean.sh b/deployment/debian-package-arm64/clean.sh
index ac143c3d0..e7bfdf8b4 100755
--- a/deployment/debian-package-arm64/clean.sh
+++ b/deployment/debian-package-arm64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/debian-package-arm64/docker-build.sh b/deployment/debian-package-arm64/docker-build.sh
index 1c75ece8e..7a13bafcb 100755
--- a/deployment/debian-package-arm64/docker-build.sh
+++ b/deployment/debian-package-arm64/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarm64
diff --git a/deployment/debian-package-arm64/package.sh b/deployment/debian-package-arm64/package.sh
index ce02b1af5..209198218 100755
--- a/deployment/debian-package-arm64/package.sh
+++ b/deployment/debian-package-arm64/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
ARCH="$( arch )"
WORKDIR="$( pwd )"
@@ -35,7 +39,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# Move the DEBs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/debian-package-armhf/Dockerfile.amd64 b/deployment/debian-package-armhf/Dockerfile.amd64
index 04dffd000..b05f10def 100644
--- a/deployment/debian-package-armhf/Dockerfile.amd64
+++ b/deployment/debian-package-armhf/Dockerfile.amd64
@@ -29,6 +29,12 @@ RUN dpkg --add-architecture armhf \
&& cd cross-gcc-packages-amd64/cross-gcc-8-armhf \
&& apt-get install -y gcc-8-source libstdc++-8-dev-armhf-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip binutils-arm-linux-gnueabihf libc6-dev:armhf linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf libfontconfig1-dev:armhf libfreetype6-dev:armhf libssl-dev:armhf liblttng-ust0:armhf libstdc++-8-dev:armhf
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/debian-package-armhf/Dockerfile.armhf b/deployment/debian-package-armhf/Dockerfile.armhf
index ed3199435..6729d8f38 100644
--- a/deployment/debian-package-armhf/Dockerfile.armhf
+++ b/deployment/debian-package-armhf/Dockerfile.armhf
@@ -21,6 +21,12 @@ RUN wget https://download.visualstudio.microsoft.com/download/pr/3cb1d917-19cc-4
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/debian-package-armhf/clean.sh b/deployment/debian-package-armhf/clean.sh
index 3898110af..35a3d3e9a 100755
--- a/deployment/debian-package-armhf/clean.sh
+++ b/deployment/debian-package-armhf/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/debian-package-armhf/docker-build.sh b/deployment/debian-package-armhf/docker-build.sh
index df35345bd..c48ccb3fb 100755
--- a/deployment/debian-package-armhf/docker-build.sh
+++ b/deployment/debian-package-armhf/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarmhf
diff --git a/deployment/debian-package-armhf/package.sh b/deployment/debian-package-armhf/package.sh
index 4393fb834..4a27dd828 100755
--- a/deployment/debian-package-armhf/package.sh
+++ b/deployment/debian-package-armhf/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
ARCH="$( arch )"
WORKDIR="$( pwd )"
@@ -35,7 +39,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# 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/Dockerfile b/deployment/debian-package-x64/Dockerfile
index 45befd76b..2f97d3944 100644
--- a/deployment/debian-package-x64/Dockerfile
+++ b/deployment/debian-package-x64/Dockerfile
@@ -21,6 +21,12 @@ RUN wget https://download.visualstudio.microsoft.com/download/pr/228832ea-805f-4
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/debian-package-x64/clean.sh b/deployment/debian-package-x64/clean.sh
index b2960fcb3..4e507bcb2 100755
--- a/deployment/debian-package-x64/clean.sh
+++ b/deployment/debian-package-x64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/debian-package-x64/docker-build.sh b/deployment/debian-package-x64/docker-build.sh
index 9781879f6..97bc45a06 100755
--- a/deployment/debian-package-x64/docker-build.sh
+++ b/deployment/debian-package-x64/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
dpkg-buildpackage -us -uc
diff --git a/deployment/debian-package-x64/package.sh b/deployment/debian-package-x64/package.sh
index 2530e253b..5a416959a 100755
--- a/deployment/debian-package-x64/package.sh
+++ b/deployment/debian-package-x64/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
WORKDIR="$( pwd )"
@@ -24,7 +28,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# 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 54d4cffba..3d2cb770f 100644
--- a/deployment/debian-package-x64/pkg-src/changelog
+++ b/deployment/debian-package-x64/pkg-src/changelog
@@ -51,297 +51,3 @@ jellyfin (10.3.0-1) unstable; urgency=medium
* New upstream version 10.3.0; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.0
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 19 Apr 2019 14:24:29 -0400
-
-jellyfin (10.2.2-1) unstable; urgency=medium
-
- * jellyfin:
- * PR968 Release 10.2.z copr autobuild
- * PR964 Install the dotnet runtime package in Fedora build
- * PR979 Build Package releases without debug turned on
- * PR990 Fix slow local image validation
- * PR991 Fix the ffmpeg compatibility
- * PR992 Add Debian armhf (Raspberry Pi) build plus crossbuild
- * PR998 Set EnableRaisingEvents to true for processes that require it
- * PR1017 Set ffmpeg+ffprobe paths in Docker container
- * jellyfin-web:
- * PR152 Go back on Media stop
- * PR156 Fix volume slider not working on nowplayingbar
-
- -- Jellyfin Packaging Team <packaging@jellyfin.org> Thu, 28 Feb 2019 15:32:16 -0500
-
-jellyfin (10.2.1-1) unstable; urgency=medium
-
- * jellyfin:
- * PR920 Fix cachedir missing from Docker container
- * PR924 Use the movie name instead of folder name
- * PR933 Semi-revert to prefer old movie grouping behaviour
- * PR948 Revert movie matching (supercedes PR933, PR924, PR739)
- * PR960 Use jellyfin/ffmpeg image
- * jellyfin-web:
- * PR136 Re-add OpenSubtitles configuration page
- * PR137 Replace HeaderEmbyServer with HeaderJellyfinServer on plugincatalog
- * PR138 Remove left-over JS for Customize Home Screen
- * PR141 Exit fullscreen automatically after video playback ends
-
- -- Jellyfin Packaging Team <packaging@jellyfin.org> Wed, 20 Feb 2019 11:36:16 -0500
-
-jellyfin (10.2.0-2) unstable; urgency=medium
-
- * jellyfin:
- * PR452 Use EF Core for Activity database
- * PR535 Clean up streambuilder
- * PR655 Support trying local branches in submodule
- * PR656 Do some logging in MediaInfoService
- * PR657 Remove conditions that are always true/false
- * PR661 Fix NullRef from progress report
- * PR663 Use TagLibSharp Nuget package
- * PR664 Revert "Fix segment_time_delta for ffmpeg 4.1"
- * PR666 Add cross-platform build for arm64
- * PR668 Return Audio objects from MusicAlbum.Tracks
- * PR671 Set EnableRaisingEvents correctly
- * PR672 Remove unconditional caching, modified since header and use ETags
- * PR677 Fix arm32 Docker
- * PR681 Fix Windows build script errors + pin ffmpeg to 4.0
- * PR686 Disable some StyleCop warnings
- * PR687 Fix some analyzer warnings
- * PR689 Fix RPM package build for fedora
- * PR702 Fix debug build on windows
- * PR706 Make another docker layer reusable
- * PR709 Fix always null expressions
- * PR710 Fix a spelling mistake
- * PR711 Remove remnants of system events
- * PR713 Fix empty statement in DidlBuilder.cs
- * PR716 Remove more compile time warnings
- * PR721 Change image dimentions from double to int
- * PR723 Minor improvements to db code
- * PR724 Move Skia back into it's own project
- * PR726 Clean up IFileSystem wrappers around stdlib.
- * PR727 Change default aspect ratio to 2/3 from 0
- * PR728 Use ffmpeg from jrottenberg/ffmpeg
- * PR732 Reworked LocalizationManager to load data async
- * PR733 Remove unused function
- * PR734 Fix more analyzer warnings
- * PR736 Start startup tasks async
- * PR737 Add AssemblyInfo for Jellyfin.Drawing.Skia
- * PR739 Change multi version logic for movies
- * PR740 Remove code for pre-installed plugins & properly check if file exists
- * PR756 Make cache dir configurable
- * PR757 Fix default aspect ratio
- * PR758 Add password field to initial setup
- * PR764 Remove dead code, made some functions properly async
- * PR769 Fix conditions where the ! was swallowed in #726
- * PR774 reimplement support for plugin repository
- * PR782 Remove commented file MediaBrowser.LocalMetadata.Savers.PersonXmlSaver
- * PR783 Update builds to use #749 and #756
- * PR788 Fix more warnings
- * PR794 Remove MoreLINQ
- * PR797 Fix all warnings
- * PR798 Cleanup around the api endpoints
- * PR800 Add CentOS and update rpm spec for the cachedir option
- * PR802 Fix build error
- * PR804 Handle new option parser properly
- * PR805 Add weblate translation status to README
- * PR807 Fix restart script in OS packages
- * PR810 Fix loading of rating files
- * PR812 Fix up the explicit docs links in the README
- * PR819 Some small changes in Device.cs and DidlBuilder.cs
- * PR822 Complete rename ImageSize -> ImageDimensions
- * PR824 Improved Docker pkgbuild
- * PR831 Move some arrays to generics
- * PR833 Add await to GetCountries in LocalizationService
- * PR834 Add donation badge and reorganize badges
- * PR838 Quick style fix
- * PR840 Fix more warnings
- * PR841 Fix OC badge to all and add forum badge
- * PR842 Use VAAPI-enabled ffmpeg
- * PR852 Use SQLitePCL.pretty.netstandard on NuGet
- * PR853 Fix poor handling of cache directories
- * PR864: Add support for ZIP plugin archives
- * PR868: Fix audio streaming via BaseProgressiveStreamingService
- * PR869: Remove DLL support and require all packages/plugins to be zip archives
- * PR872: Fix potential NullReferenceException
- * PR890: Drop ETag and use Last-Modified header
- * PR892: Add jellyfin-ffmpeg and versioning to package deps
- * PR899: DLNA: Fix race condition leading to missing device names
- * PR901: Properly dispose HttpWebResponse when the request failed to avoid 'too many open files'
- * PR909: Fix docker arm builds
- * PR910: Enhance Dockerfiles
- * PR911: Checkout submodules in Docker Hub hook
- * jellyfin-web:
- * PR51 remove more code for sync and camera roll
- * PR56 Use English for fallback translations and clean up language files
- * PR58 Css slider fixes
- * PR62 remove BOM markers
- * PR65 Fix profile image not being shown on profile page
- * PR73 Dev sync
- * PR74 Add download menu option to media items
- * PR75 User profile fixes
- * PR76 Fix syntax error caused by deminification
- * PR79 Remove unused Connect related from the frontend
- * PR80 Remove games
- * PR92 Added frontend support for a password field on setup
- * PR94 Update british strings
- * PR95 add display language option back
- * PR112 Removed seasonal theme support
- * PR116 Consolidate all strings into a single file per language
- * PR117 Fix volume slider behavior
- * PR118 Enable and fix PiP for Safari
- * PR119 Make the toggle track visible on all themes
- * PR121 Fix syntax error in site.js
- * PR127 Change sharedcomponents module to core
- * PR135 Make sure fallback culture is always available
-
- -- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 15 Feb 2019 20:51:25 -0500
-
-jellyfin (10.1.0-1) unstable; urgency=medium
-
- * jellyfin:
- * PR335 Build scripts and build system consolidation.
- * PR424 add jellyfin-web as submodule
- * PR455 Cleanup some small things
- * PR458 Clean up several minor issues and add TODOs
- * PR506 Removing tabs and trailing whitespace
- * PR508 Update internal versioning and user agents.
- * PR516 Remove useless properties from IEnvironmentInfo
- * PR520 Fix potential bug where aspect ratio would be incorrectly calculated
- * PR534 Add linux-arm and linux-arm64 native NuGet dependency.
- * PR540 Update Emby API keys to our own
- * PR541 Change ItemId to Guid in ProviderManager
- * PR556 Fix "Password Reset by PIN" page
- * PR562 Fix error with uppercase photo extension and fix typo in a log line
- * PR563 Update dev from master
- * PR566 Avoid printing stacktrace when bind to port 1900 fails
- * PR567 Shutdown gracefully when recieving a termination signal
- * PR571 Add more NuGet metadata properties
- * PR575 Reformat all C# server code to conform with code standards
- * PR576 Add code analysers for debug builds
- * PR580 Fix Docker build
- * PR582 Replace custom image parser with Skia
- * PR587 Add nuget info to Emby.Naming
- * PR589 Ensure config and log folders exist
- * PR596 Fix indentation for xml files
- * PR598 Remove MediaBrowser.Text for license violations and hackiness
- * PR606 Slim down docker image
- * PR613 Update MediaEncoding
- * PR616 Add Swagger documentation
- * PR619 Really slim down Docker container
- * PR621 Minor improvements to library scan code
- * PR622 Add unified build script and bump_version script
- * PR623 Replaced injections of ILogger with ILoggerFactory
- * PR625 Update taglib-sharp
- * PR626 Fix extra type name in parameter, add out keyword
- * PR627 Use string for ApplicationVersion
- * PR628 Update Product Name (User-Agent)
- * PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
- * PR631 Cleanup ImageProcessor and SkiaEncoder
- * PR634 Replace our TVDB key with @drakus72's which is V1
- * PR636 Allow subtitle extraction and conversion in direct streaming
- * PR637 Remove unused font
- * PR638 Removed XmlTv testfiles and nuget install
- * PR646: Fix infinite loop bug on subtitle.m3u8 request
- * PR655: Support trying local branches in submodule
- * PR661: Fix NullRef from progress report
- * PR666: Add cross-platform build for arm64
- * jellyfin-web:
- * PR1: Change webcomponents to non-minified version
- * PR4: Fix user profile regression
- * PR6: Make icon into proper ico and large PNG
- * PR7: Fix firefox failing to set password for users with no password set
- * PR8: Remove premiere stuff and fix crashes caused by earlier removals
- * PR12: Fix return from PIN reset to index.html
- * PR13: Send android clients to select server before login
- * PR14: Reimplement page to add server
- * PR16: Fix spinning circle at the end of config wizard
- * PR17: Fix directorybrower not resetting scroll
- * PR19: Set union merge for CONTRIBUTORS.md
- * PR20: Show album thumbnail and artist image in page itemdetail
- * PR26: Make the card titles clickable
- * PR27: Stop pagination and adding a library from being able to trigger multiple times
- * PR28: Add transparent nav bar to BlueRadiance theme CSS
- * PR29: Clean up imageuploader
- * PR30: Remove iap and simplify registrationservices
- * PR36: Open videos in fullscreen on android devices
- * PR37: Remove broken features from web interface
- * PR38: Fix inconsistent UI coloring around settings drawer
- * PR39: Remove back button from dashboard and metadata manager
- * PR42: Fix Home backdrop not loading
- * PR43: Filter videos by audio stream language
- * PR44: Remove filter from library collection type options
- * PR45: Fix data-backbutton logic
- * PR46: Minor changes to navbar elements
- * PR48: Remove Sync code
- * PR52: Fix progress color
- * PR53: Fix user tabs color
- * PR54: Add back button to server dashboard
-
- -- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 20 Jan 2019 23:19:46 -0500
-
-jellyfin (10.0.2-1) unstable; urgency=medium
-
- * Hotfix release
- * jellyfin/jellyfin-web#23: Update Chromecast app ID [via direct commit]
- * #540: Update Emby API keys to our own
- * #541: Change ItemId to Guid in ProviderManager
- * #566: Avoid printing stacktrace when bind to port 1900 fails
-
- -- Joshua Boniface <joshua@boniface.me> Sat, 19 Jan 2019 01:19:59 -0500
-
-jellyfin (10.0.1-1) unstable; urgency=medium
-
- * Hotfix release, corrects several small bugs from 10.0.0
- * #512: Fix CONTRIBUTORS.md formatting
- * #501: Fix regression in integer divisions in latest movies category
- * #498: Change contributing link in settings to readthedocs.io
- * #493: Remove unused values.txt resource
- * #491: Fix userprofile.js crash
- * #519: Fix the DecodeJfif function to get proper image sizes
- * #486: Add NuGet package info to plugin projects
-
- -- Joshua Boniface <joshua@boniface.me> Tue, 08 Jan 2019 20:06:01 -0500
-
-jellyfin (10.0.0-1) unstable; urgency=medium
-
- * The first Jellyfin release under our new versioning scheme
- * Numerous bugfixes and code readability improvements
- * Updated logging configuration, including flag for it and configdir
- * Updated theming including logo
- * Dozens of other improvements as documented in GitHub pull request #419
-
- -- Joshua Boniface <joshua@boniface.me> Sat, 05 Jan 2019 15:39:25 -0500
-
-jellyfin (3.5.2-5) unstable; urgency=medium
-
- * Fully GPL'd release - remove tainted code from MediaBrowser.Common
- * Several code cleanups and tweaks
-
- -- Joshua Boniface <joshua@boniface.me> Fri, 28 Dec 2018 10:26:30 -0500
-
-jellyfin (3.5.2-4) unstable; urgency=medium
-
- * Correct manifest.json bug and vdpau
-
- -- Joshua Boniface <joshua@boniface.me> Thu, 20 Dec 2018 18:31:43 -0500
-
-jellyfin (3.5.2-3) unstable; urgency=medium
-
- * Correct several bugs in 3.5.2-2 packaging
-
- -- Joshua Boniface <joshua@boniface.me> Sat, 15 Dec 2018 18:17:32 -0500
-
-jellyfin (3.5.2-2) unstable; urgency=medium
-
- * Major code updates related to rebranding and cleanup
-
- -- Joshua Boniface <joshua@boniface.me> Fri, 14 Dec 2018 00:07:46 -0500
-
-jellyfin (3.5.2-1) unstable; urgency=medium
-
- * Add ffmpeg dependency and cleanup work
-
- -- Joshua Boniface <joshua@boniface.me> Tue, 11 Dec 2018 20:55:32 -0500
-
-jellyfin (3.5.2) unstable; urgency=medium
-
- * Rename from emby-server on version 3.5.2
-
- -- Joshua Boniface <joshua@boniface.me> Sun, 9 Dec 2018 15:20:58 -0400
diff --git a/deployment/docker/build.sh b/deployment/docker/build.sh
deleted file mode 100755
index 444208c85..000000000
--- a/deployment/docker/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-build_jellyfin_docker ../.. ../../Dockerfile jellyfin:amd64-${VERSION}
-
-build_jellyfin_docker ../.. ../../Dockerfile.arm jellyfin:arm-${VERSION}
-
-#build_jellyfin_docker ../.. ../../Dockerfile.arm64v8 jellyfin:arm64v8-${VERSION}
-#build_jellyfin_docker ../.. ../../Dockerfile.arm32v7 jellyfin:arm32v7-${VERSION}
diff --git a/deployment/docker/package.sh b/deployment/docker/package.sh
deleted file mode 100755
index d74426e2f..000000000
--- a/deployment/docker/package.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-docker manifest create jellyfin:${VERSION} jellyfin:amd64-${VERSION} jellyfin:arm32v7-${VERSION} jellyfin:arm64v8-${VERSION}
-docker manifest annotate jellyfin:amd64-${VERSION} --os linux --arch amd64
-#docker manifest annotate jellyfin:arm32v7-${VERSION} --os linux --arch arm --variant armv7
-#docker manifest annotate jellyfin:arm64v8-${VERSION} --os linux --arch arm64 --variant armv8
-
-#TODO publish.sh - docker manifest push jellyfin:${VERSION}
diff --git a/deployment/fedora-package-x64/Dockerfile b/deployment/fedora-package-x64/Dockerfile
index 397c944ea..b8226b173 100644
--- a/deployment/fedora-package-x64/Dockerfile
+++ b/deployment/fedora-package-x64/Dockerfile
@@ -8,13 +8,23 @@ ARG SDK_VERSION=2.2
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
-# Prepare Fedora build environment
-RUN dnf update -y \
- && dnf install -y @buildsys-build rpmdevtools dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel \
- && dnf copr enable -y @dotnet-sig/dotnet \
+# Prepare Fedora environment
+RUN dnf update -y
+
+# Install build dependencies
+RUN dnf install -y @buildsys-build rpmdevtools dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel nodejs wget git
+
+# Install DotNET SDK
+RUN dnf copr enable -y @dotnet-sig/dotnet \
&& rpmdev-setuptree \
- && dnf install -y dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION} \
- && ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
+ && dnf install -y dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION}
+
+# Install yarn package manager
+RUN wget -q -O /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \
+ && dnf install -y yarn
+
+# Create symlinks and directories
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
&& mkdir -p ${SOURCE_DIR}/SPECS \
&& ln -s ${PLATFORM_DIR}/pkg-src/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \
&& mkdir -p ${SOURCE_DIR}/SOURCES \
diff --git a/deployment/fedora-package-x64/clean.sh b/deployment/fedora-package-x64/clean.sh
index 408167e49..700c8f1bb 100755
--- a/deployment/fedora-package-x64/clean.sh
+++ b/deployment/fedora-package-x64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/fedora-package-x64/create_tarball.sh b/deployment/fedora-package-x64/create_tarball.sh
deleted file mode 100755
index e8301c989..000000000
--- a/deployment/fedora-package-x64/create_tarball.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env bash
-
-# shellcheck disable=SC1091
-source ../common.build.sh
-
-WORKDIR="$( pwd )"
-VERSION="$( sed -ne '/^Version:/s/.* *//p' "${WORKDIR}"/pkg-src/jellyfin.spec )"
-
-package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
-pkg_src_dir="${WORKDIR}/pkg-src"
-
-GNU_TAR=1
-echo "Bundling all sources for RPM build."
-tar \
---transform "s,^\.,jellyfin-${VERSION}," \
---exclude='.git*' \
---exclude='**/.git' \
---exclude='**/.hg' \
---exclude='**/.vs' \
---exclude='**/.vscode' \
---exclude='deployment' \
---exclude='**/bin' \
---exclude='**/obj' \
---exclude='**/.nuget' \
---exclude='*.deb' \
---exclude='*.rpm' \
--czf "$pkg_src_dir/jellyfin-${VERSION}.tar.gz" \
--C "../.." ./ || GNU_TAR=0
-
-if [ $GNU_TAR -eq 0 ]; then
- echo "The installed tar binary did not support --transform. Using workaround."
- mkdir -p "${package_temporary_dir}/jellyfin"{,-"${VERSION}"}
- # Not GNU tar
- tar \
- --exclude='.git*' \
- --exclude='**/.git' \
- --exclude='**/.hg' \
- --exclude='**/.vs' \
- --exclude='**/.vscode' \
- --exclude='deployment' \
- --exclude='**/bin' \
- --exclude='**/obj' \
- --exclude='**/.nuget' \
- --exclude='*.deb' \
- --exclude='*.rpm' \
- -zcf \
- "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
- -C "../.." ./
- echo "Extracting filtered package."
- tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
- echo "Removing filtered package."
- rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
- echo "Repackaging package into final tarball."
- tar -czf "${pkg_src_dir}/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
-fi
diff --git a/deployment/fedora-package-x64/docker-build.sh b/deployment/fedora-package-x64/docker-build.sh
index cefb1652e..014f582f0 100755
--- a/deployment/fedora-package-x64/docker-build.sh
+++ b/deployment/fedora-package-x64/docker-build.sh
@@ -8,7 +8,69 @@ set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
-ls -al SOURCES/pkg-src/
+VERSION="$( grep '^Version:' ${SOURCE_DIR}/SOURCES/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Create RPM source archive
+GNU_TAR=1
+echo "Bundling all sources for RPM build."
+tar \
+--transform "s,^\.,jellyfin-${VERSION}," \
+--exclude='.git*' \
+--exclude='**/.git' \
+--exclude='**/.hg' \
+--exclude='**/.vs' \
+--exclude='**/.vscode' \
+--exclude='deployment' \
+--exclude='**/bin' \
+--exclude='**/obj' \
+--exclude='**/.nuget' \
+--exclude='*.deb' \
+--exclude='*.rpm' \
+-czf "${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-${VERSION}.tar.gz" \
+-C ${SOURCE_DIR} ./ || GNU_TAR=0
+
+if [ $GNU_TAR -eq 0 ]; then
+ echo "The installed tar binary did not support --transform. Using workaround."
+ package_temporary_dir="$( mktemp -d )"
+ mkdir -p "${package_temporary_dir}/jellyfin"
+ # Not GNU tar
+ tar \
+ --exclude='.git*' \
+ --exclude='**/.git' \
+ --exclude='**/.hg' \
+ --exclude='**/.vs' \
+ --exclude='**/.vscode' \
+ --exclude='deployment' \
+ --exclude='**/bin' \
+ --exclude='**/obj' \
+ --exclude='**/.nuget' \
+ --exclude='*.deb' \
+ --exclude='*.rpm' \
+ -czf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" \
+ -C ${SOURCE_DIR} ./
+ echo "Extracting filtered package."
+ mkdir -p "${package_temporary_dir}/jellyfin-${VERSION}"
+ tar -xzf "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}/jellyfin-${VERSION}"
+ echo "Removing filtered package."
+ rm -f "${package_temporary_dir}/jellyfin/jellyfin-${VERSION}.tar.gz"
+ echo "Repackaging package into final tarball."
+ tar -czf "${SOURCE_DIR}/SOURCES/pkg-src/jellyfin-${VERSION}.tar.gz" -C "${package_temporary_dir}" "jellyfin-${VERSION}"
+ rm -rf ${package_temporary_dir}
+fi
# Build RPM
spectool -g -R SPECS/jellyfin.spec
diff --git a/deployment/fedora-package-x64/package.sh b/deployment/fedora-package-x64/package.sh
index e659ee5e9..ae6962dd1 100755
--- a/deployment/fedora-package-x64/package.sh
+++ b/deployment/fedora-package-x64/package.sh
@@ -1,13 +1,15 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
WORKDIR="$( pwd )"
-VERSION="$( grep '^Version:' ${WORKDIR}/pkg-src/jellyfin.spec | awk '{ print $NF }' )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
-pkg_src_dir="${WORKDIR}/pkg-src"
current_user="$( whoami )"
image_name="jellyfin-fedora-build"
@@ -21,14 +23,12 @@ else
docker_sudo=""
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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# 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 d591a54e1..b4cd5b2be 100644
--- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec
+++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec
@@ -158,213 +158,3 @@ fi
- 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>
- New upstream version 10.3.0; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.0
-* Thu Feb 28 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
-- jellyfin:
-- PR968 Release 10.2.z copr autobuild
-- PR964 Install the dotnet runtime package in Fedora build
-- PR979 Build Package releases without debug turned on
-- PR990 Fix slow local image validation
-- PR991 Fix the ffmpeg compatibility
-- PR992 Add Debian armhf (Raspberry Pi) build plus crossbuild
-- PR998 Set EnableRaisingEvents to true for processes that require it
-- PR1017 Set ffmpeg+ffprobe paths in Docker container
-- jellyfin-web:
-- PR152 Go back on Media stop
-- PR156 Fix volume slider not working on nowplayingbar
-* Wed Feb 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
-- jellyfin:
-- PR920 Fix cachedir missing from Docker container
-- PR924 Use the movie name instead of folder name
-- PR933 Semi-revert to prefer old movie grouping behaviour
-- PR948 Revert movie matching (supercedes PR933, PR924, PR739)
-- PR960 Use jellyfin/ffmpeg image
-- jellyfin-web:
-- PR136 Re-add OpenSubtitles configuration page
-- PR137 Replace HeaderEmbyServer with HeaderJellyfinServer on plugincatalog
-- PR138 Remove left-over JS for Customize Home Screen
-- PR141 Exit fullscreen automatically after video playback ends
-* Fri Feb 15 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
-- jellyfin:
-- PR452 Use EF Core for Activity database
-- PR535 Clean up streambuilder
-- PR655 Support trying local branches in submodule
-- PR656 Do some logging in MediaInfoService
-- PR657 Remove conditions that are always true/false
-- PR661 Fix NullRef from progress report
-- PR663 Use TagLibSharp Nuget package
-- PR664 Revert "Fix segment_time_delta for ffmpeg 4.1"
-- PR666 Add cross-platform build for arm64
-- PR668 Return Audio objects from MusicAlbum.Tracks
-- PR671 Set EnableRaisingEvents correctly
-- PR672 Remove unconditional caching, modified since header and use ETags
-- PR677 Fix arm32 Docker
-- PR681 Fix Windows build script errors + pin ffmpeg to 4.0
-- PR686 Disable some StyleCop warnings
-- PR687 Fix some analyzer warnings
-- PR689 Fix RPM package build for fedora
-- PR702 Fix debug build on windows
-- PR706 Make another docker layer reusable
-- PR709 Fix always null expressions
-- PR710 Fix a spelling mistake
-- PR711 Remove remnants of system events
-- PR713 Fix empty statement in DidlBuilder.cs
-- PR716 Remove more compile time warnings
-- PR721 Change image dimentions from double to int
-- PR723 Minor improvements to db code
-- PR724 Move Skia back into it's own project
-- PR726 Clean up IFileSystem wrappers around stdlib.
-- PR727 Change default aspect ratio to 2/3 from 0
-- PR728 Use ffmpeg from jrottenberg/ffmpeg
-- PR732 Reworked LocalizationManager to load data async
-- PR733 Remove unused function
-- PR734 Fix more analyzer warnings
-- PR736 Start startup tasks async
-- PR737 Add AssemblyInfo for Jellyfin.Drawing.Skia
-- PR739 Change multi version logic for movies
-- PR740 Remove code for pre-installed plugins & properly check if file exists
-- PR756 Make cache dir configurable
-- PR757 Fix default aspect ratio
-- PR758 Add password field to initial setup
-- PR764 Remove dead code, made some functions properly async
-- PR769 Fix conditions where the ! was swallowed in #726
-- PR774 reimplement support for plugin repository
-- PR782 Remove commented file MediaBrowser.LocalMetadata.Savers.PersonXmlSaver
-- PR783 Update builds to use #749 and #756
-- PR788 Fix more warnings
-- PR794 Remove MoreLINQ
-- PR797 Fix all warnings
-- PR798 Cleanup around the api endpoints
-- PR800 Add CentOS and update rpm spec for the cachedir option
-- PR802 Fix build error
-- PR804 Handle new option parser properly
-- PR805 Add weblate translation status to README
-- PR807 Fix restart script in OS packages
-- PR810 Fix loading of rating files
-- PR812 Fix up the explicit docs links in the README
-- PR819 Some small changes in Device.cs and DidlBuilder.cs
-- PR822 Complete rename ImageSize -> ImageDimensions
-- PR824 Improved Docker pkgbuild
-- PR831 Move some arrays to generics
-- PR833 Add await to GetCountries in LocalizationService
-- PR834 Add donation badge and reorganize badges
-- PR838 Quick style fix
-- PR840 Fix more warnings
-- PR841 Fix OC badge to all and add forum badge
-- PR842 Use VAAPI-enabled ffmpeg
-- PR852 Use SQLitePCL.pretty.netstandard on NuGet
-- PR853 Fix poor handling of cache directories
-- PR864 Add support for ZIP plugin archives
-- PR868 Fix audio streaming via BaseProgressiveStreamingService
-- PR869 Remove DLL support and require all packages/plugins to be zip archives
-- PR872 Fix potential NullReferenceException
-- PR899: DLNA: Fix race condition leading to missing device names
-- PR890 Drop ETag and use Last-Modified header
-- PR892: Add jellyfin-ffmpeg and versioning to package deps
-- PR901: Properly dispose HttpWebResponse when the request failed to avoid 'too many open files'
-- PR909: Fix docker arm builds
-- PR910: Enhance Dockerfiles
-- PR911: Checkout submodules in Docker Hub hook
-- jellyfin-web:
-- PR51 remove more code for sync and camera roll
-- PR56 Use English for fallback translations and clean up language files
-- PR58 Css slider fixes
-- PR62 remove BOM markers
-- PR65 Fix profile image not being shown on profile page
-- PR73 Dev sync
-- PR74 Add download menu option to media items
-- PR75 User profile fixes
-- PR76 Fix syntax error caused by deminification
-- PR79 Remove unused Connect related from the frontend
-- PR80 Remove games
-- PR92 Added frontend support for a password field on setup
-- PR94 Update british strings
-- PR95 add display language option back
-- PR112 Removed seasonal theme support
-- PR116 Consolidate all strings into a single file per language
-- PR117 Fix volume slider behavior
-- PR118 Enable and fix PiP for Safari
-- PR119 Make the toggle track visible on all themes
-- PR121 Fix syntax error in site.js
-- PR127 Change sharedcomponents module to core
-- PR135 Make sure fallback culture is always available
-* Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
-- jellyfin:
-- PR335 Build scripts and build system consolidation.
-- PR424 add jellyfin-web as submodule
-- PR455 Cleanup some small things
-- PR458 Clean up several minor issues and add TODOs
-- PR506 Removing tabs and trailing whitespace
-- PR508 Update internal versioning and user agents.
-- PR516 Remove useless properties from IEnvironmentInfo
-- PR520 Fix potential bug where aspect ratio would be incorrectly calculated
-- PR534 Add linux-arm and linux-arm64 native NuGet dependency.
-- PR540 Update Emby API keys to our own
-- PR541 Change ItemId to Guid in ProviderManager
-- PR556 Fix "Password Reset by PIN" page
-- PR562 Fix error with uppercase photo extension and fix typo in a log line
-- PR563 Update dev from master
-- PR566 Avoid printing stacktrace when bind to port 1900 fails
-- PR567 Shutdown gracefully when recieving a termination signal
-- PR571 Add more NuGet metadata properties
-- PR575 Reformat all C# server code to conform with code standards
-- PR576 Add code analysers for debug builds
-- PR580 Fix Docker build
-- PR582 Replace custom image parser with Skia
-- PR587 Add nuget info to Emby.Naming
-- PR589 Ensure config and log folders exist
-- PR596 Fix indentation for xml files
-- PR598 Remove MediaBrowser.Text for license violations and hackiness
-- PR606 Slim down docker image
-- PR613 Update MediaEncoding
-- PR616 Add Swagger documentation
-- PR619 Really slim down Docker container
-- PR621 Minor improvements to library scan code
-- PR622 Add unified build script and bump_version script
-- PR623 Replaced injections of ILogger with ILoggerFactory
-- PR625 Update taglib-sharp
-- PR626 Fix extra type name in parameter, add out keyword
-- PR627 Use string for ApplicationVersion
-- PR628 Update Product Name (User-Agent)
-- PR629 Fix subtitle converter misinterpreting 0 valued endTimeTicks
-- PR631 Cleanup ImageProcessor and SkiaEncoder
-- PR634 Replace our TVDB key with @drakus72's which is V1
-- PR636 Allow subtitle extraction and conversion in direct streaming
-- PR637 Remove unused font
-- PR638 Removed XmlTv testfiles and nuget install
-- PR646: Fix infinite loop bug on subtitle.m3u8 request
-- PR655: Support trying local branches in submodule
-- PR661: Fix NullRef from progress report
-- PR666: Add cross-platform build for arm64
-- jellyfin-web:
-- PR1: Change webcomponents to non-minified version
-- PR4: Fix user profile regression
-- PR6: Make icon into proper ico and large PNG
-- PR7: Fix firefox failing to set password for users with no password set
-- PR8: Remove premiere stuff and fix crashes caused by earlier removals
-- PR12: Fix return from PIN reset to index.html
-- PR13: Send android clients to select server before login
-- PR14: Reimplement page to add server
-- PR16: Fix spinning circle at the end of config wizard
-- PR17: Fix directorybrower not resetting scroll
-- PR19: Set union merge for CONTRIBUTORS.md
-- PR20: Show album thumbnail and artist image in page itemdetail
-- PR26: Make the card titles clickable
-- PR27: Stop pagination and adding a library from being able to trigger multiple times
-- PR28: Add transparent nav bar to BlueRadiance theme CSS
-- PR29: Clean up imageuploader
-- PR30: Remove iap and simplify registrationservices
-- PR36: Open videos in fullscreen on android devices
-- PR37: Remove broken features from web interface
-- PR38: Fix inconsistent UI coloring around settings drawer
-- PR39: Remove back button from dashboard and metadata manager
-- PR42: Fix Home backdrop not loading
-- PR43: Filter videos by audio stream language
-- PR44: Remove filter from library collection type options
-- PR45: Fix data-backbutton logic
-- PR46: Minor changes to navbar elements
-- PR48: Remove Sync code
-- PR52: Fix progress color
-- PR53: Fix user tabs color
-- PR54: Add back button to server dashboard
-* Fri Jan 11 2019 Thomas Büttner <thomas@vergesslicher.tech> - 10.0.2-1
-- TODO Changelog for 10.0.2
diff --git a/deployment/linux-x64/Dockerfile b/deployment/linux-x64/Dockerfile
new file mode 100644
index 000000000..d634b55de
--- /dev/null
+++ b/deployment/linux-x64/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:10
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/linux-x64
+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 libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 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/228832ea-805f-45ab-8c88-fa36165701b9/16ce29a06031eeb09058dee94d6f5330/dotnet-sdk-2.2.401-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
+
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/linux-x64/build.sh b/deployment/linux-x64/build.sh
deleted file mode 100755
index 1f0fb62d3..000000000
--- a/deployment/linux-x64/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-build_jellyfin ../../Jellyfin.Server Release linux-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/linux-x64/clean.sh b/deployment/linux-x64/clean.sh
index 3df2d7796..c07501a7b 100755
--- a/deployment/linux-x64/clean.sh
+++ b/deployment/linux-x64/clean.sh
@@ -1,7 +1,27 @@
#!/usr/bin/env bash
-source ../common.build.sh
+keep_artifacts="${1}"
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-linux-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/linux-x64/dependencies.txt b/deployment/linux-x64/dependencies.txt
index 3d25d1bdf..bdb967096 100644
--- a/deployment/linux-x64/dependencies.txt
+++ b/deployment/linux-x64/dependencies.txt
@@ -1 +1 @@
-dotnet
+docker
diff --git a/deployment/linux-x64/docker-build.sh b/deployment/linux-x64/docker-build.sh
new file mode 100755
index 000000000..8860f943c
--- /dev/null
+++ b/deployment/linux-x64/docker-build.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Builds the TAR archive inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Get version
+version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
+
+# Build archives
+dotnet publish --configuration Release --self-contained --runtime linux-x64 --output /dist/jellyfin_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+tar -cvzf /jellyfin_${version}.portable.tar.gz -C /dist jellyfin_${version}
+rm -rf /dist/jellyfin_${version}
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/
+mv /jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/
+chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
diff --git a/deployment/linux-x64/package.sh b/deployment/linux-x64/package.sh
index 13b943ea8..dfe8a9aa4 100755
--- a/deployment/linux-x64/package.sh
+++ b/deployment/linux-x64/package.sh
@@ -1,7 +1,34 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-linux-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
+
+# 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}" ${docker_envvars}
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/* "${output_dir}"
diff --git a/deployment/macos/Dockerfile b/deployment/macos/Dockerfile
new file mode 100644
index 000000000..406a2d853
--- /dev/null
+++ b/deployment/macos/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:10
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/macos
+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 libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 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/228832ea-805f-45ab-8c88-fa36165701b9/16ce29a06031eeb09058dee94d6f5330/dotnet-sdk-2.2.401-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
+
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/macos/build.sh b/deployment/macos/build.sh
deleted file mode 100755
index d6bfb9f5e..000000000
--- a/deployment/macos/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-build_jellyfin ../../Jellyfin.Server Release osx-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/macos/clean.sh b/deployment/macos/clean.sh
index 3df2d7796..c07501a7b 100755
--- a/deployment/macos/clean.sh
+++ b/deployment/macos/clean.sh
@@ -1,7 +1,27 @@
#!/usr/bin/env bash
-source ../common.build.sh
+keep_artifacts="${1}"
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-linux-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/macos/dependencies.txt b/deployment/macos/dependencies.txt
index 3d25d1bdf..bdb967096 100644
--- a/deployment/macos/dependencies.txt
+++ b/deployment/macos/dependencies.txt
@@ -1 +1 @@
-dotnet
+docker
diff --git a/deployment/macos/docker-build.sh b/deployment/macos/docker-build.sh
new file mode 100755
index 000000000..1b4a554e6
--- /dev/null
+++ b/deployment/macos/docker-build.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Builds the TAR archive inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Get version
+version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
+
+# Build archives
+dotnet publish --configuration Release --self-contained --runtime osx-x64 --output /dist/jellyfin_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+tar -cvzf /jellyfin_${version}.portable.tar.gz -C /dist jellyfin_${version}
+rm -rf /dist/jellyfin_${version}
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/
+mv /jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/
+chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
diff --git a/deployment/macos/package.sh b/deployment/macos/package.sh
index 13b943ea8..464c0d382 100755
--- a/deployment/macos/package.sh
+++ b/deployment/macos/package.sh
@@ -1,7 +1,34 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-macos-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
+
+# 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}" ${docker_envvars}
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/* "${output_dir}"
diff --git a/deployment/portable/Dockerfile b/deployment/portable/Dockerfile
new file mode 100644
index 000000000..bdbf978fe
--- /dev/null
+++ b/deployment/portable/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:10
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/portable
+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 libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 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/228832ea-805f-45ab-8c88-fa36165701b9/16ce29a06031eeb09058dee94d6f5330/dotnet-sdk-2.2.401-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
+
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/portable/build.sh b/deployment/portable/build.sh
deleted file mode 100755
index 4f2e6363e..000000000
--- a/deployment/portable/build.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-#Magic word framework will create a non self contained build
-build_jellyfin ../../Jellyfin.Server Release framework `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/portable/clean.sh b/deployment/portable/clean.sh
index 3df2d7796..c07501a7b 100755
--- a/deployment/portable/clean.sh
+++ b/deployment/portable/clean.sh
@@ -1,7 +1,27 @@
#!/usr/bin/env bash
-source ../common.build.sh
+keep_artifacts="${1}"
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-linux-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/docker/dependencies.txt b/deployment/portable/dependencies.txt
index bdb967096..bdb967096 100644
--- a/deployment/docker/dependencies.txt
+++ b/deployment/portable/dependencies.txt
diff --git a/deployment/portable/docker-build.sh b/deployment/portable/docker-build.sh
new file mode 100755
index 000000000..0cc6e84f0
--- /dev/null
+++ b/deployment/portable/docker-build.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Builds the TAR archive inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Get version
+version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
+
+# Build archives
+dotnet publish --configuration Release --output /dist/jellyfin_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+tar -cvzf /jellyfin_${version}.portable.tar.gz -C /dist jellyfin_${version}
+rm -rf /dist/jellyfin_${version}
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/
+mv /jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/
+chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
diff --git a/deployment/portable/package.sh b/deployment/portable/package.sh
index 13b943ea8..0ceb54dda 100755
--- a/deployment/portable/package.sh
+++ b/deployment/portable/package.sh
@@ -1,7 +1,34 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-package_portable ../.. `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-portable-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
+
+# 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}" ${docker_envvars}
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/* "${output_dir}"
diff --git a/deployment/ubuntu-package-arm64/Dockerfile.amd64 b/deployment/ubuntu-package-arm64/Dockerfile.amd64
index 95525ec4e..838e70d50 100644
--- a/deployment/ubuntu-package-arm64/Dockerfile.amd64
+++ b/deployment/ubuntu-package-arm64/Dockerfile.amd64
@@ -40,6 +40,12 @@ RUN rm /etc/apt/sources.list \
&& 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 libssl-dev:arm64
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/ubuntu-package-arm64/clean.sh b/deployment/ubuntu-package-arm64/clean.sh
index c92c7fdec..82d427f9e 100755
--- a/deployment/ubuntu-package-arm64/clean.sh
+++ b/deployment/ubuntu-package-arm64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/ubuntu-package-arm64/docker-build.sh b/deployment/ubuntu-package-arm64/docker-build.sh
index 1c75ece8e..7a13bafcb 100755
--- a/deployment/ubuntu-package-arm64/docker-build.sh
+++ b/deployment/ubuntu-package-arm64/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarm64
diff --git a/deployment/ubuntu-package-arm64/package.sh b/deployment/ubuntu-package-arm64/package.sh
index 5a2bf61c8..d1140a727 100755
--- a/deployment/ubuntu-package-arm64/package.sh
+++ b/deployment/ubuntu-package-arm64/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
ARCH="$( arch )"
WORKDIR="$( pwd )"
@@ -35,7 +39,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# Move the DEBs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/ubuntu-package-armhf/Dockerfile.amd64 b/deployment/ubuntu-package-armhf/Dockerfile.amd64
index f3c7f5163..d1123e0b6 100644
--- a/deployment/ubuntu-package-armhf/Dockerfile.amd64
+++ b/deployment/ubuntu-package-armhf/Dockerfile.amd64
@@ -40,6 +40,12 @@ RUN rm /etc/apt/sources.list \
&& ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \
&& apt-get install -y gcc-6-source libstdc++6-armhf-cross binutils-arm-linux-gnueabihf 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:armhf linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf libfontconfig1-dev:armhf libfreetype6-dev:armhf liblttng-ust0:armhf libstdc++6:armhf libssl-dev:armhf
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/ubuntu-package-armhf/Dockerfile.armhf b/deployment/ubuntu-package-armhf/Dockerfile.armhf
index d67135cfe..c9e093e51 100644
--- a/deployment/ubuntu-package-armhf/Dockerfile.armhf
+++ b/deployment/ubuntu-package-armhf/Dockerfile.armhf
@@ -21,6 +21,12 @@ RUN wget https://download.visualstudio.microsoft.com/download/pr/d9f37b73-df8d-4
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
diff --git a/deployment/ubuntu-package-armhf/clean.sh b/deployment/ubuntu-package-armhf/clean.sh
index c92c7fdec..82d427f9e 100755
--- a/deployment/ubuntu-package-armhf/clean.sh
+++ b/deployment/ubuntu-package-armhf/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/ubuntu-package-armhf/docker-build.sh b/deployment/ubuntu-package-armhf/docker-build.sh
index df35345bd..c48ccb3fb 100755
--- a/deployment/ubuntu-package-armhf/docker-build.sh
+++ b/deployment/ubuntu-package-armhf/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarmhf
diff --git a/deployment/ubuntu-package-armhf/package.sh b/deployment/ubuntu-package-armhf/package.sh
index 15f55bff2..2ceb3e816 100755
--- a/deployment/ubuntu-package-armhf/package.sh
+++ b/deployment/ubuntu-package-armhf/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
ARCH="$( arch )"
WORKDIR="$( pwd )"
@@ -35,7 +39,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# 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/Dockerfile b/deployment/ubuntu-package-x64/Dockerfile
index 03c253e49..1749d2ad0 100644
--- a/deployment/ubuntu-package-x64/Dockerfile
+++ b/deployment/ubuntu-package-x64/Dockerfile
@@ -14,6 +14,12 @@ RUN apt-get update \
&& ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh \
&& mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
VOLUME ${ARTIFACT_DIR}/
COPY . ${SOURCE_DIR}/
diff --git a/deployment/ubuntu-package-x64/clean.sh b/deployment/ubuntu-package-x64/clean.sh
index c92c7fdec..82d427f9e 100755
--- a/deployment/ubuntu-package-x64/clean.sh
+++ b/deployment/ubuntu-package-x64/clean.sh
@@ -1,7 +1,5 @@
#!/usr/bin/env bash
-source ../common.build.sh
-
keep_artifacts="${1}"
WORKDIR="$( pwd )"
diff --git a/deployment/ubuntu-package-x64/docker-build.sh b/deployment/ubuntu-package-x64/docker-build.sh
index 9781879f6..97bc45a06 100755
--- a/deployment/ubuntu-package-x64/docker-build.sh
+++ b/deployment/ubuntu-package-x64/docker-build.sh
@@ -11,6 +11,20 @@ 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
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
# Build DEB
dpkg-buildpackage -us -uc
diff --git a/deployment/ubuntu-package-x64/package.sh b/deployment/ubuntu-package-x64/package.sh
index 32e6d4fd6..08c003778 100755
--- a/deployment/ubuntu-package-x64/package.sh
+++ b/deployment/ubuntu-package-x64/package.sh
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
WORKDIR="$( pwd )"
@@ -24,7 +28,7 @@ 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}"
+${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}" ${docker_envvars}
# Move the DEBs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}"
diff --git a/deployment/win-x64/Dockerfile b/deployment/win-x64/Dockerfile
new file mode 100644
index 000000000..7f64c7dae
--- /dev/null
+++ b/deployment/win-x64/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:10
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/win-x64
+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 libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 zip
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/228832ea-805f-45ab-8c88-fa36165701b9/16ce29a06031eeb09058dee94d6f5330/dotnet-sdk-2.2.401-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
+
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/win-x64/build.sh b/deployment/win-x64/build.sh
deleted file mode 100755
index 0b3046203..000000000
--- a/deployment/win-x64/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-build_jellyfin ../../Jellyfin.Server Release win-x64 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x64/clean.sh b/deployment/win-x64/clean.sh
index 3df2d7796..6c183f337 100755
--- a/deployment/win-x64/clean.sh
+++ b/deployment/win-x64/clean.sh
@@ -1,7 +1,27 @@
#!/usr/bin/env bash
-source ../common.build.sh
+keep_artifacts="${1}"
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-windows-x64-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/win-x64/dependencies.txt b/deployment/win-x64/dependencies.txt
index 3d25d1bdf..bdb967096 100644
--- a/deployment/win-x64/dependencies.txt
+++ b/deployment/win-x64/dependencies.txt
@@ -1 +1 @@
-dotnet
+docker
diff --git a/deployment/win-x64/docker-build.sh b/deployment/win-x64/docker-build.sh
new file mode 100755
index 000000000..20bf430c8
--- /dev/null
+++ b/deployment/win-x64/docker-build.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Builds the ZIP archive inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Version variables
+NSSM_VERSION="nssm-2.24-101-g897c7ad"
+NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
+FFMPEG_VERSION="ffmpeg-4.0.2-win64-static"
+FFMPEG_URL="https://ffmpeg.zeranoe.com/builds/win64/static/${FFMPEG_VERSION}.zip"
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Get version
+version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
+
+# Build binary
+dotnet publish --configuration Release --self-contained --runtime win-x64 --output /dist/jellyfin_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+
+# Prepare addins
+addin_build_dir="$( mktemp -d )"
+wget ${NSSM_URL} -O ${addin_build_dir}/nssm.zip
+wget ${FFMPEG_URL} -O ${addin_build_dir}/ffmpeg.zip
+unzip ${addin_build_dir}/nssm.zip -d ${addin_build_dir}
+cp ${addin_build_dir}/${NSSM_VERSION}/win64/nssm.exe /dist/jellyfin_${version}/nssm.exe
+unzip ${addin_build_dir}/ffmpeg.zip -d ${addin_build_dir}
+cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffmpeg.exe /dist/jellyfin_${version}/ffmpeg.exe
+cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffprobe.exe /dist/jellyfin_${version}/ffprobe.exe
+rm -rf ${addin_build_dir}
+
+# Prepare scripts
+cp ${SOURCE_DIR}/deployment/windows/legacy/install-jellyfin.ps1 /dist/jellyfin_${version}/install-jellyfin.ps1
+cp ${SOURCE_DIR}/deployment/windows/legacy/install.bat /dist/jellyfin_${version}/install.bat
+
+# Create zip package
+pushd /dist
+zip -r /jellyfin_${version}.portable.zip jellyfin_${version}
+popd
+rm -rf /dist/jellyfin_${version}
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/
+mv /jellyfin[-_]*.zip ${ARTIFACT_DIR}/
+chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
diff --git a/deployment/win-x64/package.sh b/deployment/win-x64/package.sh
index b438c28e4..a8ab190fa 100755
--- a/deployment/win-x64/package.sh
+++ b/deployment/win-x64/package.sh
@@ -1,47 +1,34 @@
#!/usr/bin/env bash
-set -x
-package_win64() (
- local NSSM_VERSION="nssm-2.24-101-g897c7ad"
- local NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
- local FFMPEG_VERSION="ffmpeg-4.0.2-win64-static"
- local FFMPEG_URL="https://ffmpeg.zeranoe.com/builds/win64/static/${FFMPEG_VERSION}.zip"
- local ROOT=${1-$DEFAULT_ROOT}
- local OUTPUT_DIR=${2-$DEFAULT_OUTPUT_DIR}
- local PKG_DIR=${3-$DEFAULT_PKG_DIR}
- local ARCHIVE_CMD="zip -r"
- # Package portable build result
- if [ -d ${OUTPUT_DIR} ]; then
- echo -e "${CYAN}Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}'.${NC}"
- local TEMP_DIR="$(mktemp -d)"
- wget ${NSSM_URL} -O ${TEMP_DIR}/nssm.zip
- wget ${FFMPEG_URL} -O ${TEMP_DIR}/ffmpeg.zip
- unzip ${TEMP_DIR}/nssm.zip -d $TEMP_DIR
- cp ${TEMP_DIR}/${NSSM_VERSION}/win64/nssm.exe ${OUTPUT_DIR}/nssm.exe
- unzip ${TEMP_DIR}/ffmpeg.zip -d $TEMP_DIR
- cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffmpeg.exe ${OUTPUT_DIR}/ffmpeg.exe
- cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffprobe.exe ${OUTPUT_DIR}/ffprobe.exe
- rm -r ${TEMP_DIR}
- cp ${ROOT}/deployment/windows/install-jellyfin.ps1 ${OUTPUT_DIR}/install-jellyfin.ps1
- cp ${ROOT}/deployment/windows/install.bat ${OUTPUT_DIR}/install.bat
- mkdir -p ${PKG_DIR}
- pushd ${OUTPUT_DIR}
- ${ARCHIVE_CMD} ${ROOT}/${PKG_DIR}/`basename "${OUTPUT_DIR}"`.zip .
- popd
- local EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' FAILED.${NC}"
- fi
- else
- echo -e "${RED}[FAIL] Build artifacts do not exist for ${OUTPUT_DIR}. Run build.sh first.${NC}"
- fi
-)
-source ../common.build.sh
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-package_win64 ../.. `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-windows-x64-build"
-#TODO setup and maybe change above code to produce the Windows native zip format.
+# 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
+
+# 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}" ${docker_envvars}
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/* "${output_dir}"
diff --git a/deployment/win-x86/Dockerfile b/deployment/win-x86/Dockerfile
new file mode 100644
index 000000000..fb5f5d6b6
--- /dev/null
+++ b/deployment/win-x86/Dockerfile
@@ -0,0 +1,37 @@
+FROM debian:10
+# Docker build arguments
+ARG SOURCE_DIR=/jellyfin
+ARG PLATFORM_DIR=/jellyfin/deployment/win-x86
+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 libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 zip
+
+# Install dotnet repository
+# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
+RUN wget https://download.visualstudio.microsoft.com/download/pr/228832ea-805f-45ab-8c88-fa36165701b9/16ce29a06031eeb09058dee94d6f5330/dotnet-sdk-2.2.401-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
+
+# Install yarn package manager
+RUN wget -q -O- https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
+ && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
+ && apt update \
+ && apt install -y yarn
+
+# Link to docker-build script
+RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
+
+VOLUME ${ARTIFACT_DIR}/
+
+COPY . ${SOURCE_DIR}/
+
+ENTRYPOINT ["/docker-build.sh"]
diff --git a/deployment/win-x86/build.sh b/deployment/win-x86/build.sh
deleted file mode 100755
index 610db356a..000000000
--- a/deployment/win-x86/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-source ../common.build.sh
-
-VERSION=`get_version ../..`
-
-build_jellyfin ../../Jellyfin.Server Release win-x86 `pwd`/dist/jellyfin_${VERSION}
diff --git a/deployment/win-x86/clean.sh b/deployment/win-x86/clean.sh
index 3df2d7796..8b78c5e4b 100755
--- a/deployment/win-x86/clean.sh
+++ b/deployment/win-x86/clean.sh
@@ -1,7 +1,27 @@
#!/usr/bin/env bash
-source ../common.build.sh
+keep_artifacts="${1}"
-VERSION=`get_version ../..`
+WORKDIR="$( pwd )"
-clean_jellyfin ../.. Release `pwd`/dist/jellyfin_${VERSION}
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-windows-x86-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/win-x86/dependencies.txt b/deployment/win-x86/dependencies.txt
index 3d25d1bdf..bdb967096 100644
--- a/deployment/win-x86/dependencies.txt
+++ b/deployment/win-x86/dependencies.txt
@@ -1 +1 @@
-dotnet
+docker
diff --git a/deployment/win-x86/docker-build.sh b/deployment/win-x86/docker-build.sh
new file mode 100755
index 000000000..c5f6e82e7
--- /dev/null
+++ b/deployment/win-x86/docker-build.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Builds the ZIP archive inside the Docker container
+
+set -o errexit
+set -o xtrace
+
+# Version variables
+NSSM_VERSION="nssm-2.24-101-g897c7ad"
+NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
+FFMPEG_VERSION="ffmpeg-4.0.2-win32-static"
+FFMPEG_URL="https://ffmpeg.zeranoe.com/builds/win32/static/${FFMPEG_VERSION}.zip"
+
+# Move to source directory
+pushd ${SOURCE_DIR}
+
+# Clone down and build Web frontend
+web_build_dir="$( mktemp -d )"
+web_target="${SOURCE_DIR}/MediaBrowser.WebDashboard/jellyfin-web"
+git clone https://github.com/jellyfin/jellyfin-web.git ${web_build_dir}/
+pushd ${web_build_dir}
+if [[ -n ${web_branch} ]]; then
+ checkout -b origin/${web_branch}
+fi
+yarn install
+mkdir -p ${web_target}
+mv dist/* ${web_target}/
+popd
+rm -rf ${web_build_dir}
+
+# Get version
+version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
+
+# Build binary
+dotnet publish --configuration Release --self-contained --runtime win-x86 --output /dist/jellyfin_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+
+# Prepare addins
+addin_build_dir="$( mktemp -d )"
+wget ${NSSM_URL} -O ${addin_build_dir}/nssm.zip
+wget ${FFMPEG_URL} -O ${addin_build_dir}/ffmpeg.zip
+unzip ${addin_build_dir}/nssm.zip -d ${addin_build_dir}
+cp ${addin_build_dir}/${NSSM_VERSION}/win64/nssm.exe /dist/jellyfin_${version}/nssm.exe
+unzip ${addin_build_dir}/ffmpeg.zip -d ${addin_build_dir}
+cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffmpeg.exe /dist/jellyfin_${version}/ffmpeg.exe
+cp ${addin_build_dir}/${FFMPEG_VERSION}/bin/ffprobe.exe /dist/jellyfin_${version}/ffprobe.exe
+rm -rf ${addin_build_dir}
+
+# Prepare scripts
+cp ${SOURCE_DIR}/deployment/windows/legacy/install-jellyfin.ps1 /dist/jellyfin_${version}/install-jellyfin.ps1
+cp ${SOURCE_DIR}/deployment/windows/legacy/install.bat /dist/jellyfin_${version}/install.bat
+
+# Create zip package
+pushd /dist
+zip -r /jellyfin_${version}.portable.zip jellyfin_${version}
+popd
+rm -rf /dist/jellyfin_${version}
+
+# Move the artifacts out
+mkdir -p ${ARTIFACT_DIR}/
+mv /jellyfin[-_]*.zip ${ARTIFACT_DIR}/
+chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
diff --git a/deployment/win-x86/package.sh b/deployment/win-x86/package.sh
index 8752d92a8..65e7e2928 100755
--- a/deployment/win-x86/package.sh
+++ b/deployment/win-x86/package.sh
@@ -1,45 +1,34 @@
#!/usr/bin/env bash
-package_win32() (
- local NSSM_VERSION="nssm-2.24-101-g897c7ad"
- local NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
- local FFMPEG_VERSION="ffmpeg-4.0.2-win32-static"
- local FFMPEG_URL="https://ffmpeg.zeranoe.com/builds/win32/static/${FFMPEG_VERSION}.zip"
- local ROOT=${1-$DEFAULT_ROOT}
- local OUTPUT_DIR=${2-$DEFAULT_OUTPUT_DIR}
- local PKG_DIR=${3-$DEFAULT_PKG_DIR}
- local ARCHIVE_CMD="zip -r"
- # Package portable build result
- if [ -d ${OUTPUT_DIR} ]; then
- echo -e "${CYAN}Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}'.${NC}"
- local TEMP_DIR="$(mktemp -d)"
- wget ${NSSM_URL} -O ${TEMP_DIR}/nssm.zip
- wget ${FFMPEG_URL} -O ${TEMP_DIR}/ffmpeg.zip
- unzip ${TEMP_DIR}/nssm.zip -d $TEMP_DIR
- cp ${TEMP_DIR}/${NSSM_VERSION}/win32/nssm.exe ${OUTPUT_DIR}/nssm.exe
- unzip ${TEMP_DIR}/ffmpeg.zip -d $TEMP_DIR
- cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffmpeg.exe ${OUTPUT_DIR}/ffmpeg.exe
- cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffprobe.exe ${OUTPUT_DIR}/ffprobe.exe
- rm -r ${TEMP_DIR}
- cp ${ROOT}/deployment/windows/install-jellyfin.ps1 ${OUTPUT_DIR}/install-jellyfin.ps1
- cp ${ROOT}/deployment/windows/install.bat ${OUTPUT_DIR}/install.bat
- mkdir -p ${PKG_DIR}
- pushd ${OUTPUT_DIR}
- ${ARCHIVE_CMD} ${ROOT}/${PKG_DIR}/`basename "${OUTPUT_DIR}"`.zip .
- popd
- local EXIT_CODE=$?
- if [ $EXIT_CODE -eq 0 ]; then
- echo -e "${GREEN}[DONE] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' complete.${NC}"
- else
- echo -e "${RED}[FAIL] Packaging build in '${OUTPUT_DIR}' for `basename "${OUTPUT_DIR}"` to '${PKG_DIR}' with root '${ROOT}' FAILED.${NC}"
- fi
- else
- echo -e "${RED}[FAIL] Build artifacts do not exist for ${OUTPUT_DIR}. Run build.sh first.${NC}"
- fi
-)
-source ../common.build.sh
-VERSION=`get_version ../..`
+args="${@}"
+declare -a docker_envvars
+for arg in ${args}; do
+ docker_envvars+=("-e ${arg}")
+done
-package_win32 ../.. `pwd`/dist/jellyfin_${VERSION}
+WORKDIR="$( pwd )"
-#TODO setup and maybe change above code to produce the Windows native zip format.
+package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
+output_dir="${WORKDIR}/pkg-dist"
+current_user="$( whoami )"
+image_name="jellyfin-windows-x86-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
+
+# 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}" ${docker_envvars}
+# Move the DEBs to the output directory
+mkdir -p "${output_dir}"
+mv "${package_temporary_dir}"/* "${output_dir}"
diff --git a/deployment/windows/build-jellyfin.ps1 b/deployment/windows/build-jellyfin.ps1
index 454c89bf6..c4fb4b995 100644
--- a/deployment/windows/build-jellyfin.ps1
+++ b/deployment/windows/build-jellyfin.ps1
@@ -51,7 +51,7 @@ function Install-FFMPEG {
Write-Warning "FFMPEG will not be installed"
}elseif($Architecture -eq 'x64'){
Write-Verbose "Downloading 64 bit FFMPEG"
- Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.0.2-win64-shared.zip -UseBasicParsing -OutFile "$tempdir/ffmpeg.zip" | Write-Verbose
+ Invoke-WebRequest -Uri https://repo.jellyfin.org/releases/server/windows/ffmpeg/jellyfin-ffmpeg.zip -UseBasicParsing -OutFile "$tempdir/ffmpeg.zip" | Write-Verbose
}else{
Write-Verbose "Downloading 32 bit FFMPEG"
Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.0.2-win32-shared.zip -UseBasicParsing -OutFile "$tempdir/ffmpeg.zip" | Write-Verbose
@@ -60,7 +60,7 @@ function Install-FFMPEG {
Expand-Archive "$tempdir/ffmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" -Force | Write-Verbose
if($Architecture -eq 'x64'){
Write-Verbose "Copying Binaries to Jellyfin location"
- Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.0.2-win64-shared/bin" | ForEach-Object {
+ Get-ChildItem "$tempdir/ffmpeg" | ForEach-Object {
Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
}
}else{
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 449aaa1a5..9188b8a02 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
-
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ -10,6 +9,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="coverlet.collector" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
new file mode 100644
index 000000000..a7848316e
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using MediaBrowser.MediaEncoding.Encoder;
+using Microsoft.Extensions.Logging.Abstractions;
+using Xunit;
+
+namespace Jellyfin.MediaEncoding.Tests
+{
+ public class EncoderValidatorTests
+ {
+ private class GetFFmpegVersionTestData : IEnumerable<object[]>
+ {
+ public IEnumerator<object[]> GetEnumerator()
+ {
+ yield return new object[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) };
+ yield return new object[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) };
+ yield return new object[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) };
+ yield return new object[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) };
+ yield return new object[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null };
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+
+ [Theory]
+ [ClassData(typeof(GetFFmpegVersionTestData))]
+ public void GetFFmpegVersionTest(string versionOutput, Version version)
+ {
+ Assert.Equal(version, EncoderValidator.GetFFmpegVersion(versionOutput));
+ }
+
+ [Theory]
+ [InlineData(EncoderValidatorTestsData.FFmpegV421Output, true)]
+ [InlineData(EncoderValidatorTestsData.FFmpegV42Output, true)]
+ [InlineData(EncoderValidatorTestsData.FFmpegV414Output, true)]
+ [InlineData(EncoderValidatorTestsData.FFmpegV404Output, true)]
+ [InlineData(EncoderValidatorTestsData.FFmpegGitUnknownOutput, false)]
+ public void ValidateVersionInternalTest(string versionOutput, bool valid)
+ {
+ var val = new EncoderValidator(new NullLogger<EncoderValidatorTests>());
+ Assert.Equal(valid, val.ValidateVersionInternal(versionOutput));
+ }
+ }
+}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs
new file mode 100644
index 000000000..12fde0770
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs
@@ -0,0 +1,66 @@
+namespace Jellyfin.MediaEncoding.Tests
+{
+ internal static class EncoderValidatorTestsData
+ {
+ public const string FFmpegV421Output = @"ffmpeg version 4.2.1 Copyright (c) 2000-2019 the FFmpeg developers
+built with gcc 9.1.1 (GCC) 20190807
+configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
+libavutil 56. 31.100 / 56. 31.100
+libavcodec 58. 54.100 / 58. 54.100
+libavformat 58. 29.100 / 58. 29.100
+libavdevice 58. 8.100 / 58. 8.100
+libavfilter 7. 57.100 / 7. 57.100
+libswscale 5. 5.100 / 5. 5.100
+libswresample 3. 5.100 / 3. 5.100
+libpostproc 55. 5.100 / 55. 5.100";
+
+ public const string FFmpegV42Output = @"ffmpeg version n4.2 Copyright (c) 2000-2019 the FFmpeg developers
+built with gcc 9.1.0 (GCC)
+configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3
+libavutil 56. 31.100 / 56. 31.100
+libavcodec 58. 54.100 / 58. 54.100
+libavformat 58. 29.100 / 58. 29.100
+libavdevice 58. 8.100 / 58. 8.100
+libavfilter 7. 57.100 / 7. 57.100
+libswscale 5. 5.100 / 5. 5.100
+libswresample 3. 5.100 / 3. 5.100
+libpostproc 55. 5.100 / 55. 5.100";
+
+ public const string FFmpegV414Output = @"ffmpeg version 4.1.4-1~deb10u1 Copyright (c) 2000-2019 the FFmpeg developers
+built with gcc 8 (Raspbian 8.3.0-6+rpi1)
+configuration: --prefix=/usr --extra-version='1~deb10u1' --toolchain=hardened --libdir=/usr/lib/arm-linux-gnueabihf --incdir=/usr/include/arm-linux-gnueabihf --arch=arm --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
+libavutil 56. 22.100 / 56. 22.100
+libavcodec 58. 35.100 / 58. 35.100
+libavformat 58. 20.100 / 58. 20.100
+libavdevice 58. 5.100 / 58. 5.100
+libavfilter 7. 40.101 / 7. 40.101
+libavresample 4. 0. 0 / 4. 0. 0
+libswscale 5. 3.100 / 5. 3.100
+libswresample 3. 3.100 / 3. 3.100
+libpostproc 55. 3.100 / 55. 3.100";
+
+ public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers
+built with gcc 8 (Debian 8.3.0-6)
+configuration: --toolchain=hardened --prefix=/usr --target-os=linux --enable-cross-compile --extra-cflags=--static --enable-gpl --enable-static --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-sdl2 --disable-xlib --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --enable-omx --enable-omx-rpi --enable-version3 --enable-vaapi --enable-vdpau --arch=amd64 --enable-nvenc --enable-nvdec
+libavutil 56. 14.100 / 56. 14.100
+libavcodec 58. 18.100 / 58. 18.100
+libavformat 58. 12.100 / 58. 12.100
+libavdevice 58. 3.100 / 58. 3.100
+libavfilter 7. 16.100 / 7. 16.100
+libswscale 5. 1.100 / 5. 1.100
+libswresample 3. 1.100 / 3. 1.100
+libpostproc 55. 1.100 / 55. 1.100";
+
+ public const string FFmpegGitUnknownOutput = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers
+built with gcc 9.1.1 (GCC) 20190716
+configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
+libavutil 56. 30.100 / 56. 30.100
+libavcodec 58. 53.101 / 58. 53.101
+libavformat 58. 28.102 / 58. 28.102
+libavdevice 58. 7.100 / 58. 7.100
+libavfilter 7. 56.101 / 7. 56.101
+libswscale 5. 4.101 / 5. 4.101
+libswresample 3. 4.100 / 3. 4.100
+libpostproc 55. 4.100 / 55. 4.100";
+ }
+}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
new file mode 100644
index 000000000..9213484fe
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netcoreapp2.2</TargetFramework>
+ <IsPackable>false</IsPackable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
+ <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+ <PackageReference Include="coverlet.collector" Version="1.1.0" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../../MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj" />
+ </ItemGroup>
+
+</Project>