Compare commits

...

33 Commits

Author SHA1 Message Date
Joshua M. Boniface 1bf3a26a61 Bump version for 10.3.3 2019-05-17 23:12:21 -04:00
Joshua M. Boniface c5760b3a40 Merge pull request #1380 from bugfixin/dlna-photo-thumb-fix
Improve Photo rendering in DLNA
2019-05-17 22:55:43 -04:00
Joshua M. Boniface 4de8bf3295 Merge pull request #1338 from cvium/fix_extras
Enforce a specific folder structure for Extras to avoid misidentification
2019-05-17 09:00:22 -04:00
bugfixin 87c8f19f19 Move DLNA thumbnail element to after larger image elements 2019-05-16 18:00:38 +00:00
Claus Vium 0ef52c739e Review changes
Untested
2019-05-16 07:27:38 +02:00
Joshua M. Boniface 0a9a6b949c Merge pull request #1372 from DrPandemic/fix-pin
Fix broken pin in 10.3.z
2019-05-14 21:54:28 -04:00
DrPandemic c22068d6b1 Fix pin bug introduced in 10.3.z.
The issue is that the new easyPassword format prepends the hash
function. This PR extract the hash from "$SHA1$_hash_".
2019-05-11 19:53:34 -04:00
Joshua M. Boniface bbc1a86b57 Merge pull request #1306 from oddstr13/pr-sudoless-build-1
Move artifact chown inside docker to avoid sudo
2019-05-10 09:25:41 -04:00
Bond-009 cd83d80f2b Merge pull request #1294 from DrPandemic/fix-download-non-ascii
Fix non-ascii filename downloads
2019-05-09 17:30:19 +02:00
Jean-Samuel Aubry-Guzzi 12721eb7dd Fix non-ascii filename downloads
Follow https://tools.ietf.org/html/rfc5987#section-3.2.2 to encode
non-ascii filenames in HTTP Content-Disposition header.
2019-05-07 19:43:04 -04:00
Claus Vium b8a09339cd Enforce extras folder structure according to Emby's wiki 2019-05-02 08:14:00 +02:00
Odd Stråbø 3634d367c1 Move artifact chown inside docker to avoid sudo 2019-05-01 20:32:15 +02:00
Claus Vium c1daea0ec7 Change owner and parent id of extras to the main media item 2019-05-01 07:47:22 +02:00
Joshua Boniface e8196fed7c Bump version for 10.3.2 2019-04-30 20:18:54 -04:00
Joshua M. Boniface 477702fbb9 Merge pull request #1324 from joshuaboniface/arm64
Add arm64 packaging for Debuntu
2019-04-30 20:07:41 -04:00
Joshua M. Boniface 2216a271bb Merge pull request #1335 from Bond-009/ffmpeglimit
Limit amount of ffmpeg processes extracting images at once
2019-04-30 20:06:24 -04:00
Bond-009 91cd7d2f6b Limit amount of ffmpeg processes extracting images at once 2019-04-30 23:35:39 +02:00
Anthony Lavado 4e681d25d9 Merge pull request #1334 from Bond-009/musicbrainzfix
Iterate over IEnumerable before disposing
2019-04-30 16:56:54 -04:00
Bond-009 06cc2891de Merge pull request #1310 from bugfixin/progressivestreamingservice-unreachable
Remove unreachable code from BaseProgressiveStreamingService
2019-04-30 22:20:54 +02:00
Bond-009 682432f55a Iterate over IEnumerable before disposing 2019-04-30 22:18:40 +02:00
Anthony Lavado 7c4cb5ec58 Merge pull request #1333 from bugfixin/easypinfix
Fix incorrect hasPassword flag when easy pin set
2019-04-30 15:36:25 -04:00
bugfixin 1df73fdeba Fix incorrect hasPassword flag when easy pin set 2019-04-30 19:16:53 +00:00
Bond-009 21ba8a0593 Merge pull request #1332 from cvium/fix_tvdb_ep_provider
Make the TvdbEpisodeProvider class Public
2019-04-30 20:59:18 +02:00
Claus Vium 08ed52eb72 Make the TvdbEpisodeProvider class Public 2019-04-30 20:08:59 +02:00
Anthony Lavado 99700e1b95 Merge pull request #1327 from joshuaboniface/disco
Support libssl1.1 for Ubuntu Disco
2019-04-30 02:38:21 -04:00
Joshua M. Boniface 4e0be95368 Merge pull request #1305 from bugfixin/passwordless-form-encoded
Fix passwordless authentication with non-json content-types
2019-04-29 23:07:04 -04:00
Joshua Boniface c8a59c8343 Support libssl1.1 for Ubuntu Disco 2019-04-29 23:03:57 -04:00
Joshua Boniface 2b2a2ed708 Add arm64 packaging for Debuntu 2019-04-29 00:56:17 -04:00
bugfixin a827a2fbcc Remove unreachable code and const trySupportSeek within BaseProgressiveStreamingService 2019-04-25 19:14:33 +00:00
Anthony Lavado f97f6b8061 Merge pull request #1296 from Bond-009/fix1234
Fix #1234
2019-04-25 01:37:02 -04:00
bugfixin 844ea9d77e Don't coalesce empty strings to null in StringMapTypeDeserializer 2019-04-25 04:36:28 +00:00
Bond_009 71479286e9 Fix #1234 2019-04-24 19:56:57 +02:00
Claus Vium 28c2ac528d Re-add content length, semi revert of changes in #1010 (#1287)
* Re-add content length, semi revert of changes in #1010
2019-04-24 14:06:54 +02:00
55 changed files with 624 additions and 168 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ RUN apt-get update \
COPY --from=ffmpeg / / COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=10.3.1 ARG JELLYFIN_WEB_VERSION=10.3.3
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \ && rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+1 -1
View File
@@ -30,7 +30,7 @@ RUN apt-get update \
&& chmod 777 /cache /config /media && chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=10.3.1 ARG JELLYFIN_WEB_VERSION=10.3.3
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \ && rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+1 -1
View File
@@ -31,7 +31,7 @@ RUN apt-get update \
&& chmod 777 /cache /config /media && chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin COPY --from=builder /jellyfin /jellyfin
ARG JELLYFIN_WEB_VERSION=10.3.1 ARG JELLYFIN_WEB_VERSION=10.3.3
RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \ RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \ && rm -rf /jellyfin/jellyfin-web \
&& mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+3 -2
View File
@@ -920,8 +920,6 @@ namespace Emby.Dlna.Didl
} }
} }
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
if (!_profile.EnableSingleAlbumArtLimit || string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase)) if (!_profile.EnableSingleAlbumArtLimit || string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase))
{ {
AddImageResElement(item, writer, 4096, 4096, "jpg", "JPEG_LRG"); AddImageResElement(item, writer, 4096, 4096, "jpg", "JPEG_LRG");
@@ -930,6 +928,9 @@ namespace Emby.Dlna.Didl
AddImageResElement(item, writer, 4096, 4096, "png", "PNG_LRG"); AddImageResElement(item, writer, 4096, 4096, "png", "PNG_LRG");
AddImageResElement(item, writer, 160, 160, "png", "PNG_TN"); AddImageResElement(item, writer, 160, 160, "png", "PNG_TN");
} }
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
} }
private void AddEmbeddedImageAsCover(string name, XmlWriter writer) private void AddEmbeddedImageAsCover(string name, XmlWriter writer)
@@ -67,6 +67,7 @@ namespace Emby.Server.Implementations.HttpServer
if (string.IsNullOrWhiteSpace(rangeHeader)) if (string.IsNullOrWhiteSpace(rangeHeader))
{ {
Headers[HeaderNames.ContentLength] = TotalContentLength.ToString(CultureInfo.InvariantCulture);
StatusCode = HttpStatusCode.OK; StatusCode = HttpStatusCode.OK;
} }
else else
@@ -99,10 +100,13 @@ namespace Emby.Server.Implementations.HttpServer
RangeStart = requestedRange.Key; RangeStart = requestedRange.Key;
RangeLength = 1 + RangeEnd - RangeStart; RangeLength = 1 + RangeEnd - RangeStart;
// Content-Length is the length of what we're serving, not the original content
var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
Headers[HeaderNames.ContentLength] = lengthString;
var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
Headers[HeaderNames.ContentRange] = rangeString; Headers[HeaderNames.ContentRange] = rangeString;
Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Range: {2}", Path, RangeHeader, rangeString); Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
} }
/// <summary> /// <summary>
@@ -638,6 +638,7 @@ namespace Emby.Server.Implementations.HttpServer
private static Task Write(IResponse response, string text) private static Task Write(IResponse response, string text)
{ {
var bOutput = Encoding.UTF8.GetBytes(text); var bOutput = Encoding.UTF8.GetBytes(text);
response.OriginalResponse.ContentLength = bOutput.Length;
return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length); return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length);
} }
@@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.HttpServer
content = Array.Empty<byte>(); content = Array.Empty<byte>();
} }
result = new StreamWriter(content, contentType); result = new StreamWriter(content, contentType, contentLength);
} }
else else
{ {
@@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.HttpServer
bytes = Array.Empty<byte>(); bytes = Array.Empty<byte>();
} }
result = new StreamWriter(bytes, contentType); result = new StreamWriter(bytes, contentType, contentLength);
} }
else else
{ {
@@ -335,13 +335,13 @@ namespace Emby.Server.Implementations.HttpServer
if (isHeadRequest) if (isHeadRequest)
{ {
var result = new StreamWriter(Array.Empty<byte>(), contentType); var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength);
AddResponseHeaders(result, responseHeaders); AddResponseHeaders(result, responseHeaders);
return result; return result;
} }
else else
{ {
var result = new StreamWriter(content, contentType); var result = new StreamWriter(content, contentType, contentLength);
AddResponseHeaders(result, responseHeaders); AddResponseHeaders(result, responseHeaders);
return result; return result;
} }
@@ -581,6 +581,11 @@ namespace Emby.Server.Implementations.HttpServer
} }
else else
{ {
if (totalContentLength.HasValue)
{
responseHeaders["Content-Length"] = totalContentLength.Value.ToString(CultureInfo.InvariantCulture);
}
if (isHeadRequest) if (isHeadRequest)
{ {
using (stream) using (stream)
@@ -624,7 +629,7 @@ namespace Emby.Server.Implementations.HttpServer
if (lastModifiedDate.HasValue) if (lastModifiedDate.HasValue)
{ {
responseHeaders[HeaderNames.LastModified] = lastModifiedDate.ToString(); responseHeaders[HeaderNames.LastModified] = lastModifiedDate.Value.ToString(CultureInfo.InvariantCulture);
} }
} }
@@ -96,6 +96,7 @@ namespace Emby.Server.Implementations.HttpServer
RangeStart = requestedRange.Key; RangeStart = requestedRange.Key;
RangeLength = 1 + RangeEnd - RangeStart; RangeLength = 1 + RangeEnd - RangeStart;
Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture);
Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
if (RangeStart > 0 && SourceStream.CanSeek) if (RangeStart > 0 && SourceStream.CanSeek)
@@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.HttpServer
public void FilterResponse(IRequest req, IResponse res, object dto) public void FilterResponse(IRequest req, IResponse res, object dto)
{ {
// Try to prevent compatibility view // Try to prevent compatibility view
res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization"); res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
res.AddHeader("Access-Control-Allow-Origin", "*"); res.AddHeader("Access-Control-Allow-Origin", "*");
@@ -58,6 +58,7 @@ namespace Emby.Server.Implementations.HttpServer
if (length > 0) if (length > 0)
{ {
res.OriginalResponse.ContentLength = length;
res.SendChunked = false; res.SendChunked = false;
} }
} }
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -49,6 +50,13 @@ namespace Emby.Server.Implementations.HttpServer
SourceStream = source; SourceStream = source;
Headers["Content-Type"] = contentType;
if (source.CanSeek)
{
Headers[HeaderNames.ContentLength] = source.Length.ToString(CultureInfo.InvariantCulture);
}
Headers[HeaderNames.ContentType] = contentType; Headers[HeaderNames.ContentType] = contentType;
} }
@@ -57,7 +65,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary> /// </summary>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param> /// <param name="contentType">Type of the content.</param>
public StreamWriter(byte[] source, string contentType) public StreamWriter(byte[] source, string contentType, int contentLength)
{ {
if (string.IsNullOrEmpty(contentType)) if (string.IsNullOrEmpty(contentType))
{ {
@@ -66,6 +74,7 @@ namespace Emby.Server.Implementations.HttpServer
SourceBytes = source; SourceBytes = source;
Headers[HeaderNames.ContentLength] = contentLength.ToString(CultureInfo.InvariantCulture);
Headers[HeaderNames.ContentType] = contentType; Headers[HeaderNames.ContentType] = contentType;
} }
@@ -550,7 +550,7 @@ namespace Emby.Server.Implementations.Library
{ {
return string.IsNullOrEmpty(user.EasyPassword) return string.IsNullOrEmpty(user.EasyPassword)
? null ? null
: user.EasyPassword; : (new PasswordHash(user.EasyPassword)).Hash;
} }
/// <summary> /// <summary>
@@ -596,7 +596,7 @@ namespace Emby.Server.Implementations.Library
} }
bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result; bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result;
bool hasConfiguredEasyPassword = string.IsNullOrEmpty(GetLocalPasswordHash(user)); bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetLocalPasswordHash(user));
bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ? bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
hasConfiguredEasyPassword : hasConfiguredEasyPassword :
@@ -43,6 +43,11 @@ namespace Emby.Server.Implementations.Services
{ {
var contentLength = bytesResponse.Length; var contentLength = bytesResponse.Length;
if (response != null)
{
response.OriginalResponse.ContentLength = contentLength;
}
if (contentLength > 0) if (contentLength > 0)
{ {
await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false); await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false);
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
@@ -20,6 +21,8 @@ namespace Emby.Server.Implementations.Services
{ {
response.StatusCode = (int)HttpStatusCode.NoContent; response.StatusCode = (int)HttpStatusCode.NoContent;
} }
response.OriginalResponse.ContentLength = 0;
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -39,11 +42,6 @@ namespace Emby.Server.Implementations.Services
response.StatusCode = httpResult.Status; response.StatusCode = httpResult.Status;
response.StatusDescription = httpResult.StatusCode.ToString(); response.StatusDescription = httpResult.StatusCode.ToString();
//if (string.IsNullOrEmpty(httpResult.ContentType))
//{
// httpResult.ContentType = defaultContentType;
//}
//response.ContentType = httpResult.ContentType;
} }
var responseOptions = result as IHasHeaders; var responseOptions = result as IHasHeaders;
@@ -53,6 +51,7 @@ namespace Emby.Server.Implementations.Services
{ {
if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase)) if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
{ {
response.OriginalResponse.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
continue; continue;
} }
@@ -72,52 +71,37 @@ namespace Emby.Server.Implementations.Services
response.ContentType += "; charset=utf-8"; response.ContentType += "; charset=utf-8";
} }
var asyncStreamWriter = result as IAsyncStreamWriter; switch (result)
if (asyncStreamWriter != null)
{ {
return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken); case IAsyncStreamWriter asyncStreamWriter:
} return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken);
case IStreamWriter streamWriter:
streamWriter.WriteTo(response.OutputStream);
return Task.CompletedTask;
case FileWriter fileWriter:
return fileWriter.WriteToAsync(response, cancellationToken);
case Stream stream:
return CopyStream(stream, response.OutputStream);
case byte[] bytes:
response.ContentType = "application/octet-stream";
response.OriginalResponse.ContentLength = bytes.Length;
var streamWriter = result as IStreamWriter; if (bytes.Length > 0)
if (streamWriter != null) {
{ return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
streamWriter.WriteTo(response.OutputStream); }
return Task.CompletedTask;
}
var fileWriter = result as FileWriter; return Task.CompletedTask;
if (fileWriter != null) case string responseText:
{ var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText);
return fileWriter.WriteToAsync(response, cancellationToken); response.OriginalResponse.ContentLength = responseTextAsBytes.Length;
}
var stream = result as Stream; if (responseTextAsBytes.Length > 0)
if (stream != null) {
{ return response.OutputStream.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
return CopyStream(stream, response.OutputStream); }
}
var bytes = result as byte[]; return Task.CompletedTask;
if (bytes != null)
{
response.ContentType = "application/octet-stream";
if (bytes.Length > 0)
{
return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
return Task.CompletedTask;
}
var responseText = result as string;
if (responseText != null)
{
bytes = Encoding.UTF8.GetBytes(responseText);
if (bytes.Length > 0)
{
return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
return Task.CompletedTask;
} }
return WriteObject(request, result, response); return WriteObject(request, result, response);
@@ -143,14 +127,13 @@ namespace Emby.Server.Implementations.Services
ms.Position = 0; ms.Position = 0;
var contentLength = ms.Length; var contentLength = ms.Length;
response.OriginalResponse.ContentLength = contentLength;
if (contentLength > 0) if (contentLength > 0)
{ {
await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false); await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
} }
} }
//serializer(result, outputStream);
} }
} }
} }
@@ -71,7 +71,7 @@ namespace Emby.Server.Implementations.Services
string propertyName = pair.Key; string propertyName = pair.Key;
string propertyTextValue = pair.Value; string propertyTextValue = pair.Value;
if (string.IsNullOrEmpty(propertyTextValue) if (propertyTextValue == null
|| !propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry) || !propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry)
|| propertySerializerEntry.PropertySetFn == null) || propertySerializerEntry.PropertySetFn == null)
{ {
+12 -1
View File
@@ -2,6 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Api.Movies; using MediaBrowser.Api.Movies;
@@ -828,7 +830,16 @@ namespace MediaBrowser.Api.Library
var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty); var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
if (!string.IsNullOrWhiteSpace(filename)) if (!string.IsNullOrWhiteSpace(filename))
{ {
headers[HeaderNames.ContentDisposition] = "attachment; filename=\"" + filename + "\""; // Kestrel doesn't support non-ASCII characters in headers
if (Regex.IsMatch(filename, "[^[:ascii:]]"))
{
// Manually encoding non-ASCII characters, following https://tools.ietf.org/html/rfc5987#section-3.2.2
headers[HeaderNames.ContentDisposition] = "attachment; filename*=UTF-8''" + WebUtility.UrlEncode(filename);
}
else
{
headers[HeaderNames.ContentDisposition] = "attachment; filename=\"" + filename + "\"";
}
} }
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -13,6 +14,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace MediaBrowser.Api.Playback.Progressive namespace MediaBrowser.Api.Playback.Progressive
@@ -279,10 +281,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// <returns>Task{System.Object}.</returns> /// <returns>Task{System.Object}.</returns>
private async Task<object> GetStaticRemoteStreamResult(StreamState state, Dictionary<string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource) private async Task<object> GetStaticRemoteStreamResult(StreamState state, Dictionary<string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
{ {
string useragent = null; state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent);
state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
var trySupportSeek = false;
var options = new HttpRequestOptions var options = new HttpRequestOptions
{ {
@@ -292,29 +291,14 @@ namespace MediaBrowser.Api.Playback.Progressive
CancellationToken = cancellationTokenSource.Token CancellationToken = cancellationTokenSource.Token
}; };
if (trySupportSeek)
{
if (!string.IsNullOrWhiteSpace(Request.QueryString[HeaderNames.Range]))
{
options.RequestHeaders[HeaderNames.Range] = Request.QueryString[HeaderNames.Range];
}
}
var response = await HttpClient.GetResponse(options).ConfigureAwait(false); var response = await HttpClient.GetResponse(options).ConfigureAwait(false);
if (trySupportSeek) responseHeaders[HeaderNames.AcceptRanges] = "none";
// Seeing cases of -1 here
if (response.ContentLength.HasValue && response.ContentLength.Value >= 0)
{ {
foreach (var name in new[] { HeaderNames.ContentRange, HeaderNames.AcceptRanges }) responseHeaders[HeaderNames.ContentLength] = response.ContentLength.Value.ToString(CultureInfo.InvariantCulture);
{
var val = response.Headers[name];
if (!string.IsNullOrWhiteSpace(val))
{
responseHeaders[name] = val;
}
}
}
else
{
responseHeaders[HeaderNames.AcceptRanges] = "none";
} }
if (isHeadRequest) if (isHeadRequest)
@@ -356,10 +340,31 @@ namespace MediaBrowser.Api.Playback.Progressive
var contentType = state.GetMimeType(outputPath); var contentType = state.GetMimeType(outputPath);
// TODO: The isHeadRequest is only here because ServiceStack will add Content-Length=0 to the response // TODO: The isHeadRequest is only here because ServiceStack will add Content-Length=0 to the response
var contentLength = state.EstimateContentLength || isHeadRequest ? GetEstimatedContentLength(state) : null;
if (contentLength.HasValue)
{
responseHeaders[HeaderNames.ContentLength] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
}
// Headers only // Headers only
if (isHeadRequest) if (isHeadRequest)
{ {
return ResultFactory.GetResult(null, Array.Empty<byte>(), contentType, responseHeaders); var streamResult = ResultFactory.GetResult(null, Array.Empty<byte>(), contentType, responseHeaders);
if (streamResult is IHasHeaders hasHeaders)
{
if (contentLength.HasValue)
{
hasHeaders.Headers[HeaderNames.ContentLength] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
}
else
{
hasHeaders.Headers.Remove(HeaderNames.ContentLength);
}
}
return streamResult;
} }
var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(outputPath); var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(outputPath);
@@ -397,5 +402,22 @@ namespace MediaBrowser.Api.Playback.Progressive
transcodingLock.Release(); transcodingLock.Release();
} }
} }
/// <summary>
/// Gets the length of the estimated content.
/// </summary>
/// <param name="state">The state.</param>
/// <returns>System.Nullable{System.Int64}.</returns>
private long? GetEstimatedContentLength(StreamState state)
{
var totalBitrate = state.TotalOutputBitrate ?? 0;
if (totalBitrate > 0 && state.RunTimeTicks.HasValue)
{
return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds / 8);
}
return null;
}
} }
} }
+62 -29
View File
@@ -78,10 +78,25 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// The trailer folder name /// The trailer folder name
/// </summary> /// </summary>
public static string TrailerFolderName = "trailers"; public const string TrailerFolderName = "trailers";
public static string ThemeSongsFolderName = "theme-music"; public const string ThemeSongsFolderName = "theme-music";
public static string ThemeSongFilename = "theme"; public const string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops"; public const string ThemeVideosFolderName = "backdrops";
public const string ExtrasFolderName = "extras";
public const string BehindTheScenesFolderName = "behind the scenes";
public const string DeletedScenesFolderName = "deleted scenes";
public const string InterviewFolderName = "interviews";
public const string SceneFolderName = "scenes";
public const string SampleFolderName = "samples";
public static readonly string[] AllExtrasTypesFolderNames = {
ExtrasFolderName,
BehindTheScenesFolderName,
DeletedScenesFolderName,
InterviewFolderName,
SceneFolderName,
SampleFolderName
};
[IgnoreDataMember] [IgnoreDataMember]
public Guid[] ThemeSongIds { get; set; } public Guid[] ThemeSongIds { get; set; }
@@ -1276,16 +1291,15 @@ namespace MediaBrowser.Controller.Entities
.Select(item => .Select(item =>
{ {
// Try to retrieve it from the db. If we don't find it, use the resolved version // Try to retrieve it from the db. If we don't find it, use the resolved version
var dbItem = LibraryManager.GetItemById(item.Id) as Video;
if (dbItem != null) if (LibraryManager.GetItemById(item.Id) is Video dbItem)
{ {
item = dbItem; item = dbItem;
} }
else else
{ {
// item is new // item is new
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeVideo; item.ExtraType = Model.Entities.ExtraType.ThemeVideo;
} }
return item; return item;
@@ -1296,33 +1310,38 @@ namespace MediaBrowser.Controller.Entities
protected virtual BaseItem[] LoadExtras(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) protected virtual BaseItem[] LoadExtras(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{ {
var files = fileSystemChildren.Where(i => i.IsDirectory) var extras = new List<Video>();
.SelectMany(i => FileSystem.GetFiles(i.FullName));
return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions()) var folders = fileSystemChildren.Where(i => i.IsDirectory).ToArray();
.OfType<Video>() foreach (var extraFolderName in AllExtrasTypesFolderNames)
.Select(item => {
{ var files = folders
// Try to retrieve it from the db. If we don't find it, use the resolved version .Where(i => string.Equals(i.Name, extraFolderName, StringComparison.OrdinalIgnoreCase))
var dbItem = LibraryManager.GetItemById(item.Id) as Video; .SelectMany(i => FileSystem.GetFiles(i.FullName));
if (dbItem != null) extras.AddRange(LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
.OfType<Video>()
.Select(item =>
{ {
item = dbItem; // Try to retrieve it from the db. If we don't find it, use the resolved version
} if (LibraryManager.GetItemById(item.Id) is Video dbItem)
else {
{ item = dbItem;
// item is new }
item.ExtraType = MediaBrowser.Model.Entities.ExtraType.Clip;
}
return item; // Use some hackery to get the extra type based on foldername
Enum.TryParse(extraFolderName.Replace(" ", ""), true, out ExtraType extraType);
item.ExtraType = extraType;
// Sort them so that the list can be easily compared for changes return item;
}).OrderBy(i => i.Path).ToArray();
// Sort them so that the list can be easily compared for changes
}).OrderBy(i => i.Path));
}
return extras.ToArray();
} }
public Task RefreshMetadata(CancellationToken cancellationToken) public Task RefreshMetadata(CancellationToken cancellationToken)
{ {
return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken); return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken);
@@ -1481,7 +1500,13 @@ namespace MediaBrowser.Controller.Entities
private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{ {
var newExtras = LoadExtras(fileSystemChildren, options.DirectoryService).Concat(LoadThemeVideos(fileSystemChildren, options.DirectoryService)).Concat(LoadThemeSongs(fileSystemChildren, options.DirectoryService)); var extras = LoadExtras(fileSystemChildren, options.DirectoryService);
var themeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
var themeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
var newExtras = new BaseItem[extras.Length + themeVideos.Length + themeSongs.Length];
extras.CopyTo(newExtras, 0);
themeVideos.CopyTo(newExtras, extras.Length);
themeSongs.CopyTo(newExtras, extras.Length + themeVideos.Length);
var newExtraIds = newExtras.Select(i => i.Id).ToArray(); var newExtraIds = newExtras.Select(i => i.Id).ToArray();
@@ -1493,7 +1518,15 @@ namespace MediaBrowser.Controller.Entities
var tasks = newExtras.Select(i => var tasks = newExtras.Select(i =>
{ {
return RefreshMetadataForOwnedItem(i, true, new MetadataRefreshOptions(options), cancellationToken); var subOptions = new MetadataRefreshOptions(options);
if (i.OwnerId != ownerId || i.ParentId != Guid.Empty)
{
i.OwnerId = ownerId;
i.ParentId = Guid.Empty;
subOptions.ForceSave = true;
}
return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
}); });
await Task.WhenAll(tasks).ConfigureAwait(false); await Task.WhenAll(tasks).ConfigureAwait(false);
@@ -53,7 +53,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private readonly int DefaultImageExtractionTimeoutMs; private readonly int DefaultImageExtractionTimeoutMs;
private readonly string StartupOptionFFmpegPath; private readonly string StartupOptionFFmpegPath;
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>(); private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
@@ -582,19 +582,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
bool ranToCompletion; bool ranToCompletion;
StartProcess(processWrapper); await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
if (timeoutMs <= 0)
{ {
timeoutMs = DefaultImageExtractionTimeoutMs; StartProcess(processWrapper);
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
if (timeoutMs <= 0)
{
timeoutMs = DefaultImageExtractionTimeoutMs;
}
ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
if (!ranToCompletion)
{
StopProcess(processWrapper, 1000);
}
} }
finally
ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
if (!ranToCompletion)
{ {
StopProcess(processWrapper, 1000); _thumbnailResourcePool.Release();
} }
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
@@ -625,7 +633,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
return time.ToString(@"hh\:mm\:ss\.fff", UsCulture); return time.ToString(@"hh\:mm\:ss\.fff", UsCulture);
} }
public async Task ExtractVideoImagesOnInterval(string[] inputFiles, public async Task ExtractVideoImagesOnInterval(
string[] inputFiles,
string container, string container,
MediaStream videoStream, MediaStream videoStream,
MediaProtocol protocol, MediaProtocol protocol,
@@ -636,8 +645,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
int? maxWidth, int? maxWidth,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var resourcePool = _thumbnailResourcePool;
var inputArgument = GetInputArgument(inputFiles, protocol); var inputArgument = GetInputArgument(inputFiles, protocol);
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture); var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture);
@@ -701,7 +708,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
_logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments); _logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); await _thumbnailResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
bool ranToCompletion = false; bool ranToCompletion = false;
@@ -742,7 +749,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
finally finally
{ {
resourcePool.Release(); _thumbnailResourcePool.Release();
} }
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
@@ -336,7 +336,7 @@ namespace MediaBrowser.Providers.Music
} }
using (var subReader = reader.ReadSubtree()) using (var subReader = reader.ReadSubtree())
{ {
return ParseReleaseList(subReader); return ParseReleaseList(subReader).ToList();
} }
} }
default: default:
@@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Music
} }
using (var subReader = reader.ReadSubtree()) using (var subReader = reader.ReadSubtree())
{ {
return ParseArtistList(subReader); return ParseArtistList(subReader).ToList();
} }
} }
default: default:
@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.TV.TheTVDB
/// <summary> /// <summary>
/// Class RemoteEpisodeProvider /// Class RemoteEpisodeProvider
/// </summary> /// </summary>
class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder public class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILogger _logger; private readonly ILogger _logger;
+2 -2
View File
@@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("10.3.1")] [assembly: AssemblyVersion("10.3.3")]
[assembly: AssemblyFileVersion("10.3.1")] [assembly: AssemblyFileVersion("10.3.3")]
+3 -1
View File
@@ -1,12 +1,14 @@
--- ---
# We just wrap `build` so this is really it # We just wrap `build` so this is really it
name: "jellyfin" name: "jellyfin"
version: "10.3.1" version: "10.3.3"
packages: packages:
- debian-package-x64 - debian-package-x64
- debian-package-armhf - debian-package-armhf
- debian-package-arm64
- ubuntu-package-x64 - ubuntu-package-x64
- ubuntu-package-armhf - ubuntu-package-armhf
- ubuntu-package-arm64
- fedora-package-x64 - fedora-package-x64
- centos-package-x64 - centos-package-x64
- linux-x64 - linux-x64
@@ -18,3 +18,4 @@ rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/rpm mkdir -p ${ARTIFACT_DIR}/rpm
mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/ mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
-3
View File
@@ -72,9 +72,6 @@ fi
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile ${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
# Build the RPMs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the RPMs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" \
|| sudo chown -R "${current_user}" "${package_temporary_dir}"
# Move the RPMs to the output directory # Move the RPMs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/rpm/* "${output_dir}" mv "${package_temporary_dir}"/rpm/* "${output_dir}"
@@ -0,0 +1,43 @@
FROM debian:9
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64
ARG ARTIFACT_DIR=/dist
ARG SDK_VERSION=2.2
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV ARCH=amd64
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/69937b49-a877-4ced-81e6-286620b390ab/8ab938cf6f5e83b2221630354160ef21/dotnet-sdk-2.2.104-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
# Prepare the cross-toolchain
RUN dpkg --add-architecture arm64 \
&& apt-get update \
&& apt-get install -y cross-gcc-dev \
&& TARGET_LIST="arm64" cross-gcc-gensource 6 \
&& cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \
&& apt-get install -y gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
# Link to Debian source dir; mkdir needed or it fails, can't force dest
RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
VOLUME ${ARTIFACT_DIR}/
COPY . ${SOURCE_DIR}/
ENTRYPOINT ["/docker-build.sh"]
#ENTRYPOINT ["/bin/bash"]
@@ -0,0 +1,34 @@
FROM debian:9
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64
ARG ARTIFACT_DIR=/dist
ARG SDK_VERSION=2.2
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV ARCH=arm64
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev liblttng-ust0
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/d9f37b73-df8d-4dfa-a905-b7648d3401d0/6312573ac13d7a8ddc16e4058f7d7dc5/dotnet-sdk-2.2.104-linux-arm.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
# Link to Debian source dir; mkdir needed or it fails, can't force dest
RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
VOLUME ${ARTIFACT_DIR}/
COPY . ${SOURCE_DIR}/
ENTRYPOINT ["/docker-build.sh"]
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
source ../common.build.sh
keep_artifacts="${1}"
WORKDIR="$( pwd )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
current_user="$( whoami )"
image_name="jellyfin-debian_arm64-build"
rm -rf "${package_temporary_dir}" &>/dev/null \
|| sudo rm -rf "${package_temporary_dir}" &>/dev/null
rm -rf "${output_dir}" &>/dev/null \
|| sudo rm -rf "${output_dir}" &>/dev/null
if [[ ${keep_artifacts} == 'n' ]]; then
docker_sudo=""
if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
&& [[ ! ${EUID:-1000} -eq 0 ]] \
&& [[ ! ${USER} == "root" ]] \
&& [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
docker_sudo=sudo
fi
${docker_sudo} docker image rm ${image_name} --force
fi
@@ -0,0 +1 @@
docker
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# Builds the DEB inside the Docker container
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
sed -i '/dotnet-sdk-2.2,/d' debian/control
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarm64
# Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
source ../common.build.sh
ARCH="$( arch )"
WORKDIR="$( pwd )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
current_user="$( whoami )"
image_name="jellyfin-debian_arm64-build"
# Determine if sudo should be used for Docker
if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
&& [[ ! ${EUID:-1000} -eq 0 ]] \
&& [[ ! ${USER} == "root" ]] \
&& [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
docker_sudo="sudo"
else
docker_sudo=""
fi
# Determine which Dockerfile to use
case $ARCH in
'x86_64')
DOCKERFILE="Dockerfile.amd64"
;;
'armv7l')
DOCKERFILE="Dockerfile.arm64"
;;
esac
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
# Build the DEBs and copy out to ${package_temporary_dir}
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
# Move the DEBs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}"
+1
View File
@@ -0,0 +1 @@
../debian-package-x64/pkg-src
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarmhf
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/ mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+2 -3
View File
@@ -30,13 +30,12 @@ case $ARCH in
;; ;;
esac esac
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image # Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE} ${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
# Build the DEBs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the DEBs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
# Move the DEBs to the output directory # Move the DEBs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}" mv "${package_temporary_dir}"/deb/* "${output_dir}"
@@ -17,3 +17,4 @@ dpkg-buildpackage -us -uc
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/ mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+2 -3
View File
@@ -19,13 +19,12 @@ else
docker_sudo="" docker_sudo=""
fi fi
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image # Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile ${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
# Build the DEBs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the DEBs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
# Move the DEBs to the output directory # Move the DEBs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}" mv "${package_temporary_dir}"/deb/* "${output_dir}"
@@ -1,3 +1,15 @@
jellyfin (10.3.3-1) unstable; urgency=medium
* New upstream version 10.3.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.3
-- Jellyfin Packaging Team <packaging@jellyfin.org> Fri, 17 May 2019 23:12:08 -0400
jellyfin (10.3.2-1) unstable; urgency=medium
* New upstream version 10.3.2; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.2
-- Jellyfin Packaging Team <packaging@jellyfin.org> Tue, 30 Apr 2019 20:18:44 -0400
jellyfin (10.3.1-1) unstable; urgency=medium jellyfin (10.3.1-1) unstable; urgency=medium
* New upstream version 10.3.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.1 * New upstream version 10.3.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.1
@@ -23,6 +23,6 @@ Depends: at,
jellyfin-ffmpeg, jellyfin-ffmpeg,
libfontconfig1, libfontconfig1,
libfreetype6, libfreetype6,
libssl1.0.0 | libssl1.0.2 libssl1.0.0 | libssl1.0.2 | libssl1.1
Description: Jellyfin is a home media server. Description: Jellyfin is a home media server.
It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development. It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development.
+10 -3
View File
@@ -6,18 +6,25 @@ SHELL := /bin/bash
HOST_ARCH := $(shell arch) HOST_ARCH := $(shell arch)
BUILD_ARCH := ${DEB_HOST_MULTIARCH} BUILD_ARCH := ${DEB_HOST_MULTIARCH}
ifeq ($(HOST_ARCH),x86_64) ifeq ($(HOST_ARCH),x86_64)
# Building AMD64
DOTNETRUNTIME := debian-x64
ifeq ($(BUILD_ARCH),arm-linux-gnueabihf) ifeq ($(BUILD_ARCH),arm-linux-gnueabihf)
# Cross-building ARM on AMD64 # Cross-building ARM on AMD64
DOTNETRUNTIME := debian-arm DOTNETRUNTIME := debian-arm
else endif
# Building AMD64 ifeq ($(BUILD_ARCH),aarch64-linux-gnu)
DOTNETRUNTIME := debian-x64 # Cross-building ARM on AMD64
DOTNETRUNTIME := debian-arm64
endif endif
endif endif
ifeq ($(HOST_ARCH),armv7l) ifeq ($(HOST_ARCH),armv7l)
# Building ARM # Building ARM
DOTNETRUNTIME := debian-arm DOTNETRUNTIME := debian-arm
endif endif
ifeq ($(HOST_ARCH),arm64)
# Building ARM
DOTNETRUNTIME := debian-arm64
endif
export DH_VERBOSE=1 export DH_VERBOSE=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1
@@ -18,3 +18,4 @@ rpmbuild -bb SPECS/jellyfin.spec --define "_sourcedir ${SOURCE_DIR}/SOURCES/pkg-
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/rpm mkdir -p ${ARTIFACT_DIR}/rpm
mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/ mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/rpm/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+2 -3
View File
@@ -23,13 +23,12 @@ fi
./create_tarball.sh ./create_tarball.sh
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image # Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile ${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
# Build the RPMs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the RPMs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" \
|| sudo chown -R "${current_user}" "${package_temporary_dir}"
# Move the RPMs to the output directory # Move the RPMs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/rpm/* "${output_dir}" mv "${package_temporary_dir}"/rpm/* "${output_dir}"
@@ -7,7 +7,7 @@
%endif %endif
Name: jellyfin Name: jellyfin
Version: 10.3.1 Version: 10.3.3
Release: 1%{?dist} Release: 1%{?dist}
Summary: The Free Software Media Browser Summary: The Free Software Media Browser
License: GPLv2 License: GPLv2
@@ -140,6 +140,10 @@ fi
%systemd_postun_with_restart jellyfin.service %systemd_postun_with_restart jellyfin.service
%changelog %changelog
* Fri May 17 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.3.3; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.3
* Tue Apr 30 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.3.2; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.2
* Sat Apr 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org> * Sat Apr 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
- New upstream version 10.3.1; release changelog at https://github.com/jellyfin/jellyfin/releases/tag/v10.3.1 - 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> * Fri Apr 19 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
@@ -0,0 +1,53 @@
FROM ubuntu:bionic
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64
ARG ARTIFACT_DIR=/dist
ARG SDK_VERSION=2.2
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV ARCH=amd64
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/69937b49-a877-4ced-81e6-286620b390ab/8ab938cf6f5e83b2221630354160ef21/dotnet-sdk-2.2.104-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
# Prepare the cross-toolchain
RUN rm /etc/apt/sources.list \
&& export CODENAME="$( lsb_release -c -s )" \
&& echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
&& echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
&& echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
&& echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \
&& echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
&& echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
&& echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
&& echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \
&& dpkg --add-architecture arm64 \
&& apt-get update \
&& apt-get install -y cross-gcc-dev \
&& TARGET_LIST="arm64" cross-gcc-gensource 6 \
&& cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \
&& ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \
&& apt-get install -y gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
# Link to Debian source dir; mkdir needed or it fails, can't force dest
RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
VOLUME ${ARTIFACT_DIR}/
COPY . ${SOURCE_DIR}/
ENTRYPOINT ["/docker-build.sh"]
@@ -0,0 +1,34 @@
FROM ubuntu:bionic
# Docker build arguments
ARG SOURCE_DIR=/jellyfin
ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64
ARG ARTIFACT_DIR=/dist
ARG SDK_VERSION=2.2
# Docker run environment
ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV ARCH=arm64
# Prepare Debian build environment
RUN apt-get update \
&& apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev liblttng-ust0
# Install dotnet repository
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
RUN wget https://download.visualstudio.microsoft.com/download/pr/d9f37b73-df8d-4dfa-a905-b7648d3401d0/6312573ac13d7a8ddc16e4058f7d7dc5/dotnet-sdk-2.2.104-linux-arm.tar.gz -O dotnet-sdk.tar.gz \
&& mkdir -p dotnet-sdk \
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
# Link to docker-build script
RUN ln -sf ${PLATFORM_DIR}/docker-build.sh /docker-build.sh
# Link to Debian source dir; mkdir needed or it fails, can't force dest
RUN mkdir -p ${SOURCE_DIR} && ln -sf ${PLATFORM_DIR}/pkg-src ${SOURCE_DIR}/debian
VOLUME ${ARTIFACT_DIR}/
COPY . ${SOURCE_DIR}/
ENTRYPOINT ["/docker-build.sh"]
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
source ../common.build.sh
keep_artifacts="${1}"
WORKDIR="$( pwd )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
current_user="$( whoami )"
image_name="jellyfin-ubuntu-build"
rm -rf "${package_temporary_dir}" &>/dev/null \
|| sudo rm -rf "${package_temporary_dir}" &>/dev/null
rm -rf "${output_dir}" &>/dev/null \
|| sudo rm -rf "${output_dir}" &>/dev/null
if [[ ${keep_artifacts} == 'n' ]]; then
docker_sudo=""
if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
&& [[ ! ${EUID:-1000} -eq 0 ]] \
&& [[ ! ${USER} == "root" ]] \
&& [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
docker_sudo=sudo
fi
${docker_sudo} docker image rm ${image_name} --force
fi
@@ -0,0 +1 @@
docker
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# Builds the DEB inside the Docker container
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
# Remove build-dep for dotnet-sdk-2.2, since it's not a package in this image
sed -i '/dotnet-sdk-2.2,/d' debian/control
# Build DEB
export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH}
dpkg-buildpackage -us -uc -aarm64
# Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
source ../common.build.sh
ARCH="$( arch )"
WORKDIR="$( pwd )"
package_temporary_dir="${WORKDIR}/pkg-dist-tmp"
output_dir="${WORKDIR}/pkg-dist"
current_user="$( whoami )"
image_name="jellyfin-ubuntu_arm64-build"
# Determine if sudo should be used for Docker
if [[ ! -z $(id -Gn | grep -q 'docker') ]] \
&& [[ ! ${EUID:-1000} -eq 0 ]] \
&& [[ ! ${USER} == "root" ]] \
&& [[ ! -z $( echo "${OSTYPE}" | grep -q "darwin" ) ]]; then
docker_sudo="sudo"
else
docker_sudo=""
fi
# Determine which Dockerfile to use
case $ARCH in
'x86_64')
DOCKERFILE="Dockerfile.amd64"
;;
'armv7l')
DOCKERFILE="Dockerfile.arm64"
;;
esac
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
# Build the DEBs and copy out to ${package_temporary_dir}
${docker_sudo} docker run --rm -v "${package_temporary_dir}:/dist" "${image_name}"
# Move the DEBs to the output directory
mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}"
+1
View File
@@ -0,0 +1 @@
../debian-package-x64/pkg-src
@@ -18,3 +18,4 @@ dpkg-buildpackage -us -uc -aarmhf
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/ mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+2 -3
View File
@@ -30,13 +30,12 @@ case $ARCH in
;; ;;
esac esac
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image # Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE} ${docker_sudo} docker build ../.. -t "${image_name}" -f ./${DOCKERFILE}
# Build the DEBs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the DEBs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
# Move the DEBs to the output directory # Move the DEBs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}" mv "${package_temporary_dir}"/deb/* "${output_dir}"
@@ -17,3 +17,4 @@ dpkg-buildpackage -us -uc
# Move the artifacts out # Move the artifacts out
mkdir -p ${ARTIFACT_DIR}/deb mkdir -p ${ARTIFACT_DIR}/deb
mv /jellyfin_* ${ARTIFACT_DIR}/deb/ mv /jellyfin_* ${ARTIFACT_DIR}/deb/
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
+2 -3
View File
@@ -19,13 +19,12 @@ else
docker_sudo="" docker_sudo=""
fi fi
# Prepare temporary package dir
mkdir -p "${package_temporary_dir}"
# Set up the build environment Docker image # Set up the build environment Docker image
${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile ${docker_sudo} docker build ../.. -t "${image_name}" -f ./Dockerfile
# Build the DEBs and copy out to ${package_temporary_dir} # 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}"
# Correct ownership on the DEBs (as current user, then as root if that fails)
chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null \
|| sudo chown -R "${current_user}" "${package_temporary_dir}" &>/dev/null
# Move the DEBs to the output directory # Move the DEBs to the output directory
mkdir -p "${output_dir}" mkdir -p "${output_dir}"
mv "${package_temporary_dir}"/deb/* "${output_dir}" mv "${package_temporary_dir}"/deb/* "${output_dir}"