Skip to content

Commit

Permalink
refactor: enable trimming feature and refactor Dockerfiles
Browse files Browse the repository at this point in the history
  • Loading branch information
jim60105 committed Dec 11, 2023
1 parent c6ff7e5 commit 15062d8
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 49 deletions.
49 changes: 36 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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"]

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"]
31 changes: 12 additions & 19 deletions Dockerfile.ubi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -44,38 +44,31 @@ 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
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"]
ENTRYPOINT ["/app/YoutubeLiveChatToDiscord"]
10 changes: 10 additions & 0 deletions Json/SourceGenerationContext.cs
Original file line number Diff line number Diff line change
@@ -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 { }
27 changes: 23 additions & 4 deletions LiveChatMonitorWorker.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -122,6 +123,10 @@ private async Task Monitoring(CancellationToken stoppingToken)
/// <param name="stoppingToken"></param>
/// <returns></returns>
/// <exception cref="FileNotFoundException"></exception>
[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");
Expand All @@ -131,7 +136,12 @@ private async Task GetVideoInfo(CancellationToken stoppingToken)
throw new FileNotFoundException(null, videoInfo.FullName);
}

Info? info = JsonConvert.DeserializeObject<Info>(await new StreamReader(videoInfo.OpenRead()).ReadToEndAsync(stoppingToken));
Info? info = JsonSerializer.Deserialize<Info>(
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;
Expand All @@ -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不鎖定。
Expand All @@ -165,12 +179,17 @@ private async Task ProcessChats(CancellationToken stoppingToken)
_position = sr.BaseStream.Position;
if (string.IsNullOrEmpty(str)) continue;

Chat? chat = JsonConvert.DeserializeObject<Chat>(str);
Chat? chat = JsonSerializer.Deserialize<Chat>(
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);
Expand Down
14 changes: 7 additions & 7 deletions Models/Info.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;

namespace YoutubeLiveChatToDiscord.Models;

Expand All @@ -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; }
}

Expand Down Expand Up @@ -873,10 +873,10 @@ public class AutomaticCaptions
public List<Ca>? ca { get; set; }
public List<Ceb>? ceb { get; set; }

[JsonProperty("zh-Hans")]
[JsonPropertyName("zh-Hans")]
public List<ZhHan>? ZhHans { get; set; }

[JsonProperty("zh-Hant")]
[JsonPropertyName("zh-Hant")]
public List<ZhHant>? ZhHant { get; set; }
public List<Co>? co { get; set; }
public List<Hr>? hr { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions YoutubeLiveChatToDiscord.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>dotnet-LiveChatToDiscord-ACE24696-7DD5-4164-8805-CF76B90CBA6C</UserSecretsId>
<ServerGarbageCollection>false</ServerGarbageCollection>
<InvariantGlobalization>true</InvariantGlobalization>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
<ServerGarbageCollection>false</ServerGarbageCollection>
<DockerfileFastModeStage>debug</DockerfileFastModeStage>
<IsTrimmable>true</IsTrimmable>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net.Webhook" Version="3.13.0" />
Expand All @@ -22,6 +24,5 @@
<TrimmerRootAssembly Include="Discord.Net.Rest" />
<TrimmerRootAssembly Include="Newtonsoft.Json" />
<TrimmerRootAssembly Include="YoutubeDLSharp" />
<TrimmerRootAssembly Include="YoutubeLiveChatToDiscord" />
</ItemGroup>
</Project>

0 comments on commit 15062d8

Please sign in to comment.