diff --git a/Dockerfile b/Dockerfile
index c480d5b..809b038 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,13 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
### Base image for yt-dlp
-FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS base
+FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-alpine AS base
WORKDIR /app
RUN apk add --no-cache tzdata python3 && \
apk add --no-cache --virtual build-deps musl-dev gcc g++ python3-dev py3-pip && \
python3 -m venv /venv && \
source /venv/bin/activate && \
- pip install yt-dlp && \
+ pip install --no-cache-dir yt-dlp && \
pip uninstall -y setuptools pip && \
apk del build-deps
@@ -20,26 +20,49 @@ ENV DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
### Debug image (same as base image)
### Rename for VS fast mode stage debugging
-FROM base AS debug
+FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS debug
+
+WORKDIR /app
+RUN apk add --no-cache tzdata python3 && \
+ apk add --no-cache --virtual build-deps musl-dev gcc g++ python3-dev py3-pip && \
+ python3 -m venv /venv && \
+ source /venv/bin/activate && \
+ pip install --no-cache-dir yt-dlp && \
+ pip uninstall -y setuptools pip && \
+ apk del build-deps
+
+ENV PATH="/venv/bin:$PATH"
+ENV TZ=Asia/Taipei
+
+# Disable file locking on Unix
+# https://github.com/dotnet/runtime/issues/34126#issuecomment-1104981659
+ENV DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
+
### Build .NET
-FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
ARG BUILD_CONFIGURATION=Release
+ARG TARGETARCH
WORKDIR /src
+
COPY ["YoutubeLiveChatToDiscord.csproj", "."]
-ARG TARGETPLATFORM
-RUN dotnet restore "YoutubeLiveChatToDiscord.csproj"
+RUN dotnet restore -a $TARGETARCH "YoutubeLiveChatToDiscord.csproj"
FROM build AS publish
COPY . .
ARG BUILD_CONFIGURATION=Release
-ARG TARGETPLATFORM
-RUN dotnet publish "YoutubeLiveChatToDiscord.csproj" --no-self-contained -p:PublishTrimmed=false -c $BUILD_CONFIGURATION -o /app/publish
+ARG TARGETARCH
+RUN dotnet publish "YoutubeLiveChatToDiscord.csproj" -a $TARGETARCH -c $BUILD_CONFIGURATION -o /app/publish --self-contained true
+
### Final image
FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-RUN chown -R 1001:1001 /app
-USER 1001
-ENTRYPOINT ["dotnet", "YoutubeLiveChatToDiscord.dll"]
\ No newline at end of file
+
+ENV PATH="/app:$PATH"
+
+RUN mkdir -p /app && chown -R $APP_UID:$APP_UID /app
+COPY --from=publish --chown=$APP_UID:$APP_UID /app/publish/YoutubeLiveChatToDiscord /app/YoutubeLiveChatToDiscord
+COPY --from=publish --chown=$APP_UID:$APP_UID /app/publish/appsettings.json /app/appsettings.json
+
+USER $APP_UID
+ENTRYPOINT ["/app/YoutubeLiveChatToDiscord"]
\ No newline at end of file
diff --git a/Dockerfile.ubi b/Dockerfile.ubi
index c341fa2..0a48839 100644
--- a/Dockerfile.ubi
+++ b/Dockerfile.ubi
@@ -13,8 +13,8 @@ RUN microdnf -y install python3.11 python3.11-pip && \
microdnf -y clean all
RUN python3.11 -m venv /venv && \
- source /venv/bin/activate &&\
- pip3.11 install yt-dlp && \
+ source /venv/bin/activate && \
+ pip3.11 install --no-cache-dir yt-dlp && \
pip3.11 uninstall -y setuptools pip && \
microdnf -y remove python3.11-pip && \
microdnf -y clean all
@@ -44,29 +44,21 @@ RUN microdnf -y install dotnet-sdk-8.0
### Build .NET
-FROM registry.access.redhat.com/ubi8/dotnet-80 AS build
+FROM --platform=$BUILDPLATFORM registry.access.redhat.com/ubi8/dotnet-80 AS build
USER 0
ARG BUILD_CONFIGURATION=Release
+ARG TARGETARCH
WORKDIR /src
-COPY YoutubeLiveChatToDiscord.csproj .
-ARG TARGETPLATFORM
-RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
- dotnet restore "YoutubeLiveChatToDiscord.csproj" -r linux-x64; \
- elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
- dotnet restore "YoutubeLiveChatToDiscord.csproj" -r linux-arm64; \
- fi
+COPY ["YoutubeLiveChatToDiscord.csproj", "."]
+RUN dotnet restore -a $TARGETARCH "YoutubeLiveChatToDiscord.csproj"
FROM build AS publish
COPY . .
ARG BUILD_CONFIGURATION=Release
-ARG TARGETPLATFORM
-RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
- dotnet publish "YoutubeLiveChatToDiscord.csproj" -c $BUILD_CONFIGURATION -o /app/publish -r linux-x64; \
- elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
- dotnet publish "YoutubeLiveChatToDiscord.csproj" -c $BUILD_CONFIGURATION -o /app/publish -r linux-arm64; \
- fi
+ARG TARGETARCH
+RUN dotnet publish "YoutubeLiveChatToDiscord.csproj" -a $TARGETARCH -c $BUILD_CONFIGURATION -o /app/publish --self-contained true
### Final image
@@ -74,8 +66,9 @@ FROM base AS final
ENV PATH="/app:$PATH"
-COPY --link --chown=1001:1001 --from=publish /app/publish .
+RUN mkdir -p /app && chown -R 1001:1001 /app
+COPY --from=publish --chown=1001:1001 /app/publish/YoutubeLiveChatToDiscord /app/YoutubeLiveChatToDiscord
+COPY --from=publish --chown=1001:1001 /app/publish/appsettings.json /app/appsettings.json
USER 1001
-
-ENTRYPOINT ["YoutubeLiveChatToDiscord"]
\ No newline at end of file
+ENTRYPOINT ["/app/YoutubeLiveChatToDiscord"]
\ No newline at end of file
diff --git a/Json/SourceGenerationContext.cs b/Json/SourceGenerationContext.cs
new file mode 100644
index 0000000..0adb2e6
--- /dev/null
+++ b/Json/SourceGenerationContext.cs
@@ -0,0 +1,10 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using YoutubeLiveChatToDiscord.Models;
+
+// Must read:
+// https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation?pivots=dotnet-8-0
+[JsonSerializable(typeof(Info))]
+[JsonSerializable(typeof(Chat))]
+[JsonSourceGenerationOptions(WriteIndented = true, AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip)]
+internal partial class SourceGenerationContext : JsonSerializerContext { }
diff --git a/LiveChatMonitorWorker.cs b/LiveChatMonitorWorker.cs
index 2c3b3bb..2d75178 100644
--- a/LiveChatMonitorWorker.cs
+++ b/LiveChatMonitorWorker.cs
@@ -1,6 +1,7 @@
using Discord;
using Discord.Webhook;
-using Newtonsoft.Json;
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json;
using YoutubeLiveChatToDiscord.Models;
using YoutubeLiveChatToDiscord.Services;
@@ -122,6 +123,10 @@ private async Task Monitoring(CancellationToken stoppingToken)
///
///
///
+ [UnconditionalSuppressMessage(
+ "Trimming",
+ "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
+ Justification = $"{nameof(SourceGenerationContext)} is used.")]
private async Task GetVideoInfo(CancellationToken stoppingToken)
{
FileInfo videoInfo = new($"{_id}.info.json");
@@ -131,7 +136,12 @@ private async Task GetVideoInfo(CancellationToken stoppingToken)
throw new FileNotFoundException(null, videoInfo.FullName);
}
- Info? info = JsonConvert.DeserializeObject(await new StreamReader(videoInfo.OpenRead()).ReadToEndAsync(stoppingToken));
+ Info? info = JsonSerializer.Deserialize(
+ await new StreamReader(videoInfo.OpenRead()).ReadToEndAsync(stoppingToken),
+ options: new()
+ {
+ TypeInfoResolver = SourceGenerationContext.Default
+ });
string? Title = info?.title;
string? ChannelId = info?.channel_id;
string? thumb = info?.thumbnail;
@@ -141,6 +151,10 @@ private async Task GetVideoInfo(CancellationToken stoppingToken)
Environment.SetEnvironmentVariable("VIDEO_THUMB", thumb);
}
+ [UnconditionalSuppressMessage(
+ "Trimming",
+ "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
+ Justification = $"{nameof(SourceGenerationContext)} is used.")]
private async Task ProcessChats(CancellationToken stoppingToken)
{
// Notice: yt-dlp在Linux會使用lock鎖定此檔案,在Windows不鎖定。
@@ -165,12 +179,17 @@ private async Task ProcessChats(CancellationToken stoppingToken)
_position = sr.BaseStream.Position;
if (string.IsNullOrEmpty(str)) continue;
- Chat? chat = JsonConvert.DeserializeObject(str);
+ Chat? chat = JsonSerializer.Deserialize(
+ str,
+ options: new()
+ {
+ TypeInfoResolver = SourceGenerationContext.Default
+ });
if (null == chat) continue;
await BuildRequestAndSendToDiscord(chat, stoppingToken);
}
- catch (JsonSerializationException e)
+ catch (JsonException e)
{
_logger.LogError("{error}", e.Message);
_logger.LogError("{originalString}", str);
diff --git a/Models/Info.cs b/Models/Info.cs
index b157807..5251f1e 100644
--- a/Models/Info.cs
+++ b/Models/Info.cs
@@ -1,4 +1,4 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace YoutubeLiveChatToDiscord.Models;
@@ -11,17 +11,17 @@ namespace YoutubeLiveChatToDiscord.Models;
#pragma warning disable IDE1006 // 命名樣式
public class HttpHeaders
{
- [JsonProperty("User-Agent")]
+ [JsonPropertyName("User-Agent")]
public string? UserAgent { get; set; }
public string? Accept { get; set; }
- [JsonProperty("Accept-Encoding")]
+ [JsonPropertyName("Accept-Encoding")]
public string? AcceptEncoding { get; set; }
- [JsonProperty("Accept-Language")]
+ [JsonPropertyName("Accept-Language")]
public string? AcceptLanguage { get; set; }
- [JsonProperty("Sec-Fetch-Mode")]
+ [JsonPropertyName("Sec-Fetch-Mode")]
public string? SecFetchMode { get; set; }
}
@@ -873,10 +873,10 @@ public class AutomaticCaptions
public List? ca { get; set; }
public List? ceb { get; set; }
- [JsonProperty("zh-Hans")]
+ [JsonPropertyName("zh-Hans")]
public List? ZhHans { get; set; }
- [JsonProperty("zh-Hant")]
+ [JsonPropertyName("zh-Hant")]
public List? ZhHant { get; set; }
public List? co { get; set; }
public List
? hr { get; set; }
diff --git a/README.md b/README.md
index 25c3357..8483b8d 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ Two parameters need to be passed in:
- Discord Webhook URL
```sh
-docker run -rm ghcr.io/jim60105/youtubelivechattodiscord [Video_Id] [Discord_Webhook_Url]
+docker run --rm ghcr.io/jim60105/youtubelivechattodiscord [Video_Id] [Discord_Webhook_Url]
```
Also available at [quay.io](https://quay.io/jim60105/youtubelivechattodiscord)
diff --git a/YoutubeLiveChatToDiscord.csproj b/YoutubeLiveChatToDiscord.csproj
index c9227ed..e6223aa 100644
--- a/YoutubeLiveChatToDiscord.csproj
+++ b/YoutubeLiveChatToDiscord.csproj
@@ -4,13 +4,15 @@
enable
enable
dotnet-LiveChatToDiscord-ACE24696-7DD5-4164-8805-CF76B90CBA6C
+ false
+ true
+ true
+ true
+ true
+ true
Linux
.
- false
debug
- true
- true
- full
@@ -22,6 +24,5 @@
-
\ No newline at end of file