diff options
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 @@ -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> @@ -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> |
