diff --git a/.github/workflows/BuildDockerPipeline.yml b/.github/workflows/BuildDockerPipeline.yml index 2e29492e..e1787863 100644 --- a/.github/workflows/BuildDockerPipeline.yml +++ b/.github/workflows/BuildDockerPipeline.yml @@ -96,6 +96,7 @@ jobs: push: ${{ (github.event_name != 'pull_request') }} build-args: | LABEL_VERSION=${{ steps.nbgv.outputs.SemVer2 }} + DBGTOOL_INSTALL=${{ endsWith(github.ref, 'refs/heads/main') && '' || 'True' }} tags: | ${{ secrets.DOCKER_HUB_USERNAME }}/plexcleaner:${{ endsWith(github.ref, 'refs/heads/main') && 'latest' || 'develop' }} ${{ secrets.DOCKER_HUB_USERNAME }}/plexcleaner:${{ steps.nbgv.outputs.SemVer2 }} diff --git a/.vscode/launch.json b/.vscode/launch.json index e19fa68f..0837420d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -21,6 +21,13 @@ "name": ".NET Core Attach", "type": "coreclr", "request": "attach" - } + }, + { + "name": "Docker .NET Core Attach", + "type": "docker", + "request": "attach", + "platform": "netCore", + "processId": "${command:pickRemoteProcess}" + } ] } \ No newline at end of file diff --git a/Docker/Dockerfile b/Docker/Dockerfile index a47d665d..8dea438f 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,17 +1,29 @@ # Test in docker shell: -# docker run -it --rm ubuntu:latest /bin/bash +# docker run -it --rm --pull always --name Testing ubuntu:latest /bin/bash # export DEBIAN_FRONTEND=noninteractive + +# Test in develop shell: +# docker run -it --rm --pull always --name Testing --volume /data/media:/media:rw ptr727/plexcleaner:develop /bin/bash + + # Test Docker build: # dotnet publish ./PlexCleaner/PlexCleaner.csproj --runtime linux-x64 --self-contained false --output ./Docker/PlexCleaner # docker build ./Docker -# Ignore docker layer cache + +# Ignore docker layer cache: # docker build --no-cache ./Docker +# Set arguments: +# docker build --build-arg DBGTOOL_INSTALL=True ./Docker + +# Pass container output instead of buildkit suppressing it: +# docker build --progress=plain --build-arg DBGTOOL_INSTALL=True ./Docker + # Build from Ubuntu LTS as base image FROM ubuntu:latest -# Update the version at build time +# Set the version at build time ARG LABEL_VERSION="1.0.0.0" LABEL name="PlexCleaner" \ @@ -28,7 +40,15 @@ ARG DEBIAN_FRONTEND=noninteractive # Install prerequisites RUN apt-get update \ && apt-get upgrade -y \ - && apt-get install -y apt-utils wget apt-transport-https lsb-release software-properties-common p7zip-full locales locales-all \ + && apt-get install -y \ + apt-transport-https \ + apt-utils \ + locales \ + locales-all \ + lsb-core \ + p7zip-full \ + software-properties-common \ + wget \ && locale-gen --no-purge en_US en_US.UTF-8 # Set locale to UTF-8 after running locale-gen @@ -38,6 +58,7 @@ ENV LANG=en_US.UTF-8 \ # TODO: Build could be optimized by combining RUN layers, but that makes troubleshooting more difficult + # Install .NET 6 Runtime # https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu # TODO: Substitute ubuntu with $(lsb_release -si | tr '[:upper:]' '[:lower:]') @@ -48,33 +69,45 @@ ENV DOTNET_RUNNING_IN_CONTAINER=true \ DOTNET_USE_POLLING_FILE_WATCHER=true \ NUGET_XMLDOC_MODE=skip -RUN wget -q https://packages.microsoft.com/config/ubuntu/$(lsb_release -sr)/packages-microsoft-prod.deb \ +# Conditionally install SDK and Debug tools, else just runtime +# Test for empty or not empty string using -z or -n +ARG DBGTOOL_INSTALL="" + +RUN wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -sr)/packages-microsoft-prod.deb \ && dpkg -i packages-microsoft-prod.deb \ && apt-get update \ - && apt-get install -y dotnet-runtime-6.0 \ + && if [ -n "$DBGTOOL_INSTALL" ] ; then \ + apt-get install -y dotnet-sdk-6.0 \ + && wget https://aka.ms/getvsdbgsh \ + && sh getvsdbgsh -v latest -l /vsdbg \ + && rm getvsdbgsh ; \ + else \ + apt-get install -y dotnet-runtime-6.0 ; \ + fi \ + && rm packages-microsoft-prod.deb \ && dotnet --info + # Install MediaInfo # https://mediaarea.net/en/MediaInfo/Download/Ubuntu # https://mediaarea.net/en/Repos -RUN wget -q https://mediaarea.net/repo/deb/repo-mediaarea_1.0-19_all.deb \ - && dpkg -i repo-mediaarea_1.0-19_all.deb \ +RUN wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-20_all.deb \ + && dpkg -i repo-mediaarea_1.0-20_all.deb \ && apt-get update \ && apt-get install -y mediainfo \ + && rm repo-mediaarea_1.0-20_all.deb \ && mediainfo --version + # Install MKVToolNix # https://mkvtoolnix.download/downloads.html#ubuntu - -# Avoid apt-key output should not be parsed warning -ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 - -RUN wget -q -O - https://mkvtoolnix.download/gpg-pub-moritzbunkus.txt | apt-key add - \ - && sh -c 'echo "deb https://mkvtoolnix.download/ubuntu/ $(lsb_release -sc) main" >> /etc/apt/sources.list.d/bunkus.org.list' \ +RUN wget -O /usr/share/keyrings/gpg-pub-moritzbunkus.gpg https://mkvtoolnix.download/gpg-pub-moritzbunkus.gpg \ + && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/gpg-pub-moritzbunkus.gpg] https://mkvtoolnix.download/ubuntu/ $(lsb_release -sc) main" >> /etc/apt/sources.list.d/mkvtoolnix.list' \ && apt-get update \ && apt-get install -y mkvtoolnix \ && mkvmerge --version + # Install FfMpeg # https://launchpad.net/~savoury1/+archive/ubuntu/ffmpeg5 RUN add-apt-repository -y ppa:savoury1/graphics \ @@ -85,6 +118,7 @@ RUN add-apt-repository -y ppa:savoury1/graphics \ && apt-get install -y ffmpeg \ && ffmpeg -version + # Install HandBrake # Depends on FfMpeg, install FfMpeg first # https://launchpad.net/~savoury1/+archive/ubuntu/handbrake @@ -93,11 +127,13 @@ RUN add-apt-repository -y ppa:savoury1/handbrake \ && apt-get install -y handbrake-cli \ && HandBrakeCLI --version + # Cleanup RUN apt-get autoremove -y \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* + # Copy PlexCleaner # Build externally # dotnet publish ./PlexCleaner/PlexCleaner.csproj --runtime linux-x64 --self-contained false --output ./Docker/PlexCleaner diff --git a/HISTORY.md b/HISTORY.md index 2935dcf1..4815774d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,15 @@ Utility to optimize media files for Direct Play in Plex, Emby, Jellyfin. ## Release History +- Version 2.8: + - Added parallel file processing support: + - Greatly improves throughput on high core count systems, where a single instance of FFmpeg or HandBrake can't utilize all available processing power. + - Enable parallel processing by using the `--parallel` command line option. + - The default thread count is equal to half the number of system cores. + - Override the default thread count by using the `--threadcount` option, e.g. `PlexCleaner --parallel --threadcount 2`. + - The executing ThreadId is logged to output, this helps with correlating between sequential and logical operations. + - Interactive console output from tools are disabled when parallel processing is enabled, this avoids console overwrites. + - General refactoring, bug fixes, and upstream package updates. - Version 2.7: - Log names of all processed files that are in `VerifyFailed` state at the end of the `process` command. - Prevent duplicate entries in `ProcessOptions:FileIgnoreList` setting when `VerifyOptions:RegisterInvalidFiles` is set, could happen when using `--reprocess 2`. diff --git a/PlexCleaner/CommandLineOptions.cs b/PlexCleaner/CommandLineOptions.cs index 18587c6e..fde22fc4 100644 --- a/PlexCleaner/CommandLineOptions.cs +++ b/PlexCleaner/CommandLineOptions.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.CommandLine; using System.CommandLine.NamingConventionBinder; +using System.CommandLine.Parsing; +using System.Linq; namespace PlexCleaner; @@ -16,6 +18,14 @@ public class CommandLineOptions public int ReProcess { get; set; } public bool Parallel { get; set; } public int ThreadCount { get; set; } + public bool Debug { get; set; } + + public static int Invoke() + { + // TODO: https://github.com/dotnet/command-line-api/issues/1781 + RootCommand rootCommand = CommandLineOptions.CreateRootCommand(); + return rootCommand.Invoke(CommandLineStringSplitter.Instance.Split(Environment.CommandLine).ToArray()[1..]); + } public static RootCommand CreateRootCommand() { @@ -112,6 +122,14 @@ private static void AddGlobalOptions(RootCommand command) Description = "Number of threads to use for parallel processing", IsRequired = false }); + + // Wait for debugger to attach, optional + command.AddGlobalOption( + new Option("--debug") + { + Description = "Wait for debugger to attach", + IsRequired = false + }); } private static Command CreateDefaultSettingsCommand() diff --git a/PlexCleaner/PlexCleaner.csproj b/PlexCleaner/PlexCleaner.csproj index 1ff8ec65..77d5a121 100644 --- a/PlexCleaner/PlexCleaner.csproj +++ b/PlexCleaner/PlexCleaner.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/PlexCleaner/Program.cs b/PlexCleaner/Program.cs index 45517230..8056f1bd 100644 --- a/PlexCleaner/Program.cs +++ b/PlexCleaner/Program.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.CommandLine; using System.IO; using System.Linq; using System.Reflection; @@ -17,20 +16,21 @@ internal class Program { private static int Main() { + // Wait for debugger to attach + WaitForDebugger(); + // Create default logger CreateLogger(null); - // Create a 15s timer to keep the system from going to sleep - // TODO: The system occasionally still goes to sleep when debugging, why? + // Create a timer to keep the system from going to sleep KeepAwake.PreventSleep(); - using System.Timers.Timer keepAwakeTimer = new(15 * 1000); + using System.Timers.Timer keepAwakeTimer = new(30 * 1000); keepAwakeTimer.Elapsed += KeepAwake.OnTimedEvent; keepAwakeTimer.AutoReset = true; keepAwakeTimer.Start(); // Create the commandline and execute commands - RootCommand rootCommand = CommandLineOptions.CreateRootCommand(); - int ret = rootCommand.Invoke(Environment.CommandLine); + int ret = CommandLineOptions.Invoke(); // Stop the timer keepAwakeTimer.Stop(); @@ -43,6 +43,24 @@ private static int Main() return ret; } + private static void WaitForDebugger() + { + // Use the raw commandline and look for --debug + if (Environment.CommandLine.Contains("--debug")) + { + // Wait for a debugger to be attached + Console.WriteLine("Waiting for debugger to attach..."); + while (!System.Diagnostics.Debugger.IsAttached) + { + Thread.Sleep(100); + } + Console.WriteLine("Debugger attached."); + + // Break into the debugger + System.Diagnostics.Debugger.Break(); + } + } + private static void CreateLogger(string logfile) { // Enable Serilog debug output to the console diff --git a/PlexCleaner/Properties/launchSettings.json b/PlexCleaner/Properties/launchSettings.json index abf4330a..0509053b 100644 --- a/PlexCleaner/Properties/launchSettings.json +++ b/PlexCleaner/Properties/launchSettings.json @@ -86,6 +86,10 @@ "Process Snippets Parallel": { "commandName": "Project", "commandLineArgs": "--parallel --settingsfile \"PlexCleaner.json\" --logfile \"PlexCleaner.log\" process --testsnippets --mediafiles \"D:\\Test\"" + }, + "Debugger": { + "commandName": "Project", + "commandLineArgs": "--debugger" } } } \ No newline at end of file diff --git a/README.md b/README.md index b80689c0..9282a119 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,13 @@ Docker images are published on [Docker Hub](https://hub.docker.com/u/ptr727/plex ## Release Notes -- Version 2.8: - - Added parallel file processing support: - - Greatly improves throughput on high core count systems, where a single instance of FFmpeg or HandBrake can't utilize all available processing power. - - Enable parallel processing by using the `--parallel` command line option. - - The default thread count is equal to half the number of system cores. - - Override the default thread count by using the `--threadcount` option, e.g. `PlexCleaner --parallel --threadcount 2`. - - The executing ThreadId is logged to output, this helps with correlating between sequential and logical operations. - - Interactive console output from tools are disabled when parallel processing is enabled, this avoids console overwrites. - - General refactoring, bug fixes, and upstream package updates. +- Version 2.9: + - Added remote docker container debug support. + - `develop` tagged docker builds use the `Debug` build target, and will now install the .NET SDK and the [VsDbg](https://aka.ms/getvsdbgsh) .NET Debugger. + - Added a `--debug` command line option that will wait for a debugger to be attached on launch. + - Remote debugging in docker over SSH can be done using [VSCode](https://github.com/OmniSharp/omnisharp-vscode/wiki/Attaching-to-remote-processes) or [Visual Studio](https://docs.microsoft.com/en-us/visualstudio/debugger/attach-to-process-running-in-docker-container?view=vs-2022). + - Updated Dockerfile with latest Linux install steps for MediaInfo and MKVToolNix. + - Updated System.CommandLine usage to accommodate Beta 4 breaking changes. - See [Release History](./HISTORY.md) for older Release Notes. ## Questions or Issues @@ -91,11 +89,15 @@ Example, run in an interactive shell: # The host "/data/media" directory is mapped to the container "/media" directory # Replace the volume mappings to suit your needs -# Pull the latest container version -docker pull ptr727/plexcleaner - # Run the bash shell in an interactive session -docker run -it --rm --volume /data/media:/media:rw ptr727/plexcleaner /bin/bash +docker run \ + -it \ + --rm \ + --pull always \ + --name PlexCleaner \ + --volume /data/media:/media:rw \ + ptr727/plexcleaner \ + /bin/bash # Create default settings file # Edit the settings file to suit your needs @@ -128,13 +130,12 @@ screen -r sudo chown -R nobody:users /data/media sudo chmod -R u=rwx,g=rwx+s,o=rx /data/media -# Pull the latest container version -docker pull ptr727/plexcleaner - # Run the process command in an interactive session docker run \ -it \ --rm \ + --pull always \ + --name PlexCleaner \ --user nobody:users \ --env TZ=America/Los_Angeles \ --volume /data/media:/media:rw \ @@ -429,6 +430,7 @@ Options: --logappend Append to the log file vs. default overwrite --parallel Enable parallel processing --threadcount Number of threads to use for parallel processing + --debug Wait for debugger to attach --version Show version information -?, -h, --help Show help and usage information @@ -473,6 +475,7 @@ Options: --logappend Append to the log file vs. default overwrite --parallel Enable parallel processing --threadcount Number of threads to use for parallel processing + --debug Wait for debugger to attach -?, -h, --help Show help and usage information ``` diff --git a/version.json b/version.json index 054a9e98..ecf1ef86 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.8", + "version": "2.9", "publicReleaseRefSpec": [ "^refs/heads/main$" ],