Code Monkey home page Code Monkey logo

plexcleaner's Introduction

PlexCleaner

Utility to optimize media files for Direct Play in Plex, Emby, Jellyfin.

License

Licensed under the MIT License
GitHub License

Build

Code and Pipeline is on GitHub.
Binary releases are published on GitHub Releases.
Docker images are published on Docker Hub.

Status

Release Status
Docker Status
Last Commit
Last Build

Releases

GitHub Release
GitHub Pre-Release
Docker Latest
Docker Develop

Release Notes

  • Version 3.7:
    • Added ProcessOptions:IgnoreFiles to support skipping (not deleting) sample files per discussions request.
      • Wildcard characters * and ? are supported, e.g. *.sample or *.sample.*.
      • Wildcard support now also allows excluding temporary UnRaid FuseFS files, e.g. *.fuse_hidden*.
    • Settings JSON schema changed from v3 to v4.
      • ProcessOptions:KeepExtensions has been deprecated, existing values will be converted to ProcessOptions:IgnoreExtensions.
        • E.g. ProcessOptions:KeepExtensions : .nfo will be converted to ProcessOptions:IgnoreExtensions : *.nfo.
      • ConvertOptions:FfMpegOptions:Output has been deprecated, no need to for user changeable values.
      • ConvertOptions:FfMpegOptions:Global no longer require defaults values, only add custom values for e.g. hardware acceleration options, existing values will be converted.
        • E.g. -analyzeduration 2147483647 -probesize 2147483647 -hwaccel cuda -hwaccel_output_format cuda will be converted to -hwaccel cuda -hwaccel_output_format cuda.
        • E.g. -analyzeduration 2147483647 -probesize 2147483647 will be converted to ``.
    • Changed JSON serialization from Newtonsoft.Json to .NET native Text.Json.
    • Changed JSON schema generation from Newtonsoft.Json.Schema to JsonSchema.Net.Generation.
    • Fixed issue with old settings schemas not upgrading as expected, and updated associated unit tests to help catch this next time.
    • Disabling Alpine Edge builds, Handbrake is failing to install, again.
      • Will re-enable Alpine builds if Alpine 3.20 and Handbrake is stable.
  • Version 3.6:
    • Disabling Alpine 3.19 release builds and switching to Alpine Edge.
      • Handbrake is only available on Edge, and mixing released and Edge versions cause too many issues.
      • Alpine stable release builds will no longer be built, or not until Handbrake is supported on stable releases (v3.20 May 2024).
      • Alpine Edge builds will be tagged as alpine-edge.
  • Version 3.5:
    • Download 7-Zip builds from GitHub, fixes issue #324.
    • Update Alpine Docker image to 3.19.
  • See Release History for older Release Notes.

Questions or Issues

  • Use the Discussions forum for general questions.
  • Refer to the Issues tracker for known problems.
  • Report bugs in the Issues tracker.

Use Cases

The objective of PlexCleaner is to modify media content such that it will always Direct Play in Plex, Emby, Jellyfin.

Below are examples of issues that can be resolved using the primary process command:

  • Container file formats other than MKV are not supported by all platforms, re-multiplex to MKV.
  • Licensing for some codecs like MPEG-2 prevents hardware decoding, re-encode to H.264.
  • Some video codecs like MPEG-4 or VC-1 cause playback issues, re-encode to H.264.
  • Some H.264 video profiles like Constrained Baseline@30 cause playback issues, re-encode to H.264 High@40.
  • On some displays interlaced video cause playback issues, deinterlace using HandBrake and the --comb-detect --decomb options.
  • Some audio codecs like Vorbis or WMAPro are not supported by the client platform, re-encode to AC3.
  • Some subtitle tracks like VOBsub cause hangs when the MuxingMode attribute is not set, re-multiplex to set the correct MuxingMode.
  • Automatic audio and subtitle track selection requires the track language to be set, set the language for unknown tracks.
  • Duplicate audio or subtitle tracks of the same language cause issues with player track selection, delete duplicate tracks, and keep the best quality audio tracks.
  • Corrupt media streams cause playback issues, verify stream integrity, and try to automatically repair by re-encoding.
  • Some WiFi or 100Mbps Ethernet connected devices with small read buffers hang when playing high bitrate content, warn when media bitrate exceeds the network bitrate.
  • Dolby Vision is only supported on DV capable displays, warn when the HDR profile is Dolby Vision (profile 5) vs. Dolby Vision / SMPTE ST 2086 (profile 7) that supports DV and HDR10/HDR10+ displays.
  • EIA-608 Closed Captions embedded in video streams can't be disabled or managed from the player, remove embedded closed captions from video streams.
  • See the process command for more details.

Performance Considerations

  • To improve processing performance of large media collections, the media file attributes and processing state is cached in sidecar files. (filename.mkv -> filename.PlexCleaner)
  • Sidecar files allow re-processing of the same files to be very fast as the state will be read from the sidecar vs. re-computed from the media file.
  • The sidecar maintains a hash of small parts of the media file (timestamps are unreliable), and the media file will be reprocessed when a change in the media file is detected.
  • Re-multiplexing is an IO intensive operation and re-encoding is a CPU intensive operation.
  • Parallel processing, using the --parallel option, is useful when a single instance of FFmpeg or HandBrake does not saturate all the available CPU resources.
  • When parallel processing is enabled, the default thread count is half the number of system cores, and can be changed using the --threadcount option.
  • Processing can be interrupted using Ctrl-C, if using sidecar files restarting will skip previously verified files.
  • Processing very large media collections on docker may result in a very large docker log file, set appropriate docker logging options.

Installation

Docker builds are the easiest and most up to date way to run, and can be used on any platform that supports linux/amd64, linux/arm64, or linux/arm/v7 architectures.
Alternatively, install directly on Windows, Linux, or MacOS following the provided instructions.

Docker

  • Builds are published on Docker Hub.
  • See the Docker README for image and tag details.
    • latest is based on Ubuntu and contains the most up to date media processing tools.
    • alpine is based on Alpine and is the smallest image.
    • debian is based on Debian and supports the most platforms.
  • Images are updated weekly with the latest upstream updates.
  • The container has all the prerequisite 3rd party tools pre-installed.
  • Map your host volumes, and make sure the user has permission to access and modify media files.
  • The container is intended to be used in interactive mode, for long running operations run in a screen session.
  • See examples below for instructions on getting started.

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

# Run the bash shell in an interactive session
docker run \
  -it \
  --rm \
  --pull always \
  --name PlexCleaner \
  --volume /data/media:/media:rw \
  docker.io/ptr727/plexcleaner \
  /bin/bash

# Create default settings file
# Edit the settings file to suit your needs
/PlexCleaner/PlexCleaner \
  defaultsettings \
  --settingsfile /media/PlexCleaner/PlexCleaner.json

# Process media files
/PlexCleaner/PlexCleaner \
  --logfile /media/PlexCleaner/PlexCleaner.log \
  process \
  --settingsfile /media/PlexCleaner/PlexCleaner.json \
  --mediafiles /media/Movies \
  --mediafiles /media/Series

# Exit the interactive session
exit

Example, run in a screen session:

# Start a new screen session
screen

# Or attach to an existing screen session
screen -r

# Make sure the media file permissions allow writing
sudo chown -R nobody:users /data/media
sudo chmod -R u=rwx,g=rwx+s,o=rx /data/media

# Run the process command in an interactive session
docker run \
  -it \
  --rm \
  --pull always \
  --log-driver json-file --log-opt max-size=10m \
  --name PlexCleaner \
  --user nobody:users \
  --env TZ=America/Los_Angeles \
  --volume /data/media:/media:rw \
  docker.io/ptr727/plexcleaner \
  /PlexCleaner/PlexCleaner \
    --logfile /media/PlexCleaner/PlexCleaner.log \
    --logwarning \
    process \
    --settingsfile /media/PlexCleaner/PlexCleaner.json \
    --parallel \
    --mediafiles /media/Movies \
    --mediafiles /media/Series

Windows

  • Install the .NET Runtime.
  • Download PlexCleaner and extract the pre-compiled binaries.
  • Or compile from code using Visual Studio or VSCode or the .NET SDK.
  • Create a default JSON settings file using the defaultsettings command:
    • PlexCleaner defaultsettings --settingsfile PlexCleaner.json
    • Modify the settings to suit your needs.
  • Download the required 3rd party tools using the checkfornewtools command:
    • PlexCleaner checkfornewtools --settingsfile PlexCleaner.json
    • The default Tools folder will be created in the same folder as the PlexCleaner binary file.
    • The tool version information will be stored in Tools\Tools.json.
    • Keep the 3rd party tools updated by periodically running the checkfornewtools command, or update tools on every run by setting ToolsOptions:AutoUpdate to true.
  • If required, e.g. no internet connectivity, the tools can be manually downloaded and extracted:
    • FfMpeg Full, e.g. ffmpeg-6.0-full.7z: \Tools\FfMpeg
    • HandBrake CLI x64, e.g. HandBrakeCLI-1.6.1-win-x86_64.zip: \Tools\HandBrake
    • MediaInfo CLI x64, e.g. MediaInfo_CLI_23.07_Windows_x64.zip: \Tools\MediaInfo
    • MkvToolNix Portable x64, e.g. mkvtoolnix-64-bit-79.0.7z: \Tools\MkvToolNix
    • 7-Zip Extra, e.g. 7z2301-extra.7z: \Tools\SevenZip
    • Disable automatic tool updates by setting ToolsOptions:AutoUpdate to false.

Linux

  • Automatic downloading of Linux 3rd party tools are not supported, consider using the Docker build instead.
  • Manually install the 3rd party tools, e.g. following steps similar to the Docker file commands.
  • Download PlexCleaner and extract the pre-compiled binaries matching your platform.
  • Or compile from code using the .NET SDK.
  • Create a default JSON settings file using the defaultsettings command:
    • ./PlexCleaner defaultsettings --settingsfile PlexCleaner.json
    • Modify the settings to suit your needs.

macOS

  • macOS x64 and Arm64 binaries are built as part of Releases, but are untested.

Configuration

Create a default JSON configuration file by running:
PlexCleaner defaultsettings --settingsfile PlexCleaner.json

Refer to the commented default JSON settings file for usage.

Custom FFmpeg and HandBrake CLI Parameters

The ConvertOptions:FfMpegOptions and ConvertOptions:HandBrakeOptions settings allows for custom CLI parameters to be used during processing.

Note that hardware assisted encoding options are operating system, hardware, and tool version specific.
Refer to the Jellyfin hardware acceleration docs for hints on usage.
The example configurations are from documentation and minimal testing with Intel QuickSync on Windows only, please discuss and post working configurations in Discussions.

FFmpeg Options

See the FFmpeg documentation for complete commandline option details.
The typical FFmpeg commandline is ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url}.
E.g. ffmpeg "-analyzeduration 2147483647 -probesize 2147483647 -i "/media/foo.mkv" -max_muxing_queue_size 1024 -abort_on empty_output -hide_banner -nostats -map 0 -c:v libx265 -crf 26 -preset medium -c:a ac3 -c:s copy -f matroska "/media/bar.mkv"

Settings allows for custom configuration of:

  • FfMpegOptions:Global: Custom hardware global options, e.g. -hwaccel cuda -hwaccel_output_format cuda
  • FfMpegOptions:Video: Video encoder options following the -c:v parameter, e.g. libx264 -crf 22 -preset medium
  • FfMpegOptions:Audio: Audio encoder options following the -c:a parameter, e.g. ac3

Get encoder options:

  • List all supported encoders: ffmpeg -encoders
  • List options supported by an encoder: ffmpeg -h encoder=libsvtav1

Example video encoder options:

  • H.264: libx264 -crf 22 -preset medium
  • H.265: libx265 -crf 26 -preset medium
  • AV1: libsvtav1 -crf 30 -preset 5

Example hardware assisted video encoding options:

  • NVidia NVENC:
    • See NVidia and FFmpeg documentation.
    • View NVENC encoder options: ffmpeg -h encoder=h264_nvenc
    • FfMpegOptions:Global: -hwaccel cuda -hwaccel_output_format cuda
    • FfMpegOptions:Video: h264_nvenc -crf 22 -preset medium
  • Intel QuickSync:
    • See FFmpeg documentation.
    • View QuickSync encoder options: ffmpeg -h encoder=h264_qsv
    • FfMpegOptions:Global: -hwaccel qsv -hwaccel_output_format qsv
    • FfMpegOptions:Video: h264_qsv -crf 22 -preset medium

HandBrake Options

See the HandBrake documentation for complete commandline option details.
The typical HandBrake commandline is HandBrakeCLI [options] -i <source> -o <destination>.
E.g. HandBrakeCLI --input "/media/foo.mkv" --output "/media/bar.mkv" --format av_mkv --encoder x265 --quality 26 --encoder-preset medium --comb-detect --decomb --all-audio --aencoder copy --audio-fallback ac3

Settings allows for custom configuration of:

  • HandBrakeOptions:Video: Video encoder options following the --encode parameter, e.g. x264 --quality 22 --encoder-preset medium
  • HandBrakeOptions:Audio: Audio encoder options following the --aencode parameter, e.g. copy --audio-fallback ac3

Get encoder options:

  • List all supported encoders: HandBrakeCLI.exe --help
  • List presets supported by an encoder: HandBrakeCLI --encoder-preset-list svt_av1

Example video encoder options:

  • H.264: x264 --quality 22 --encoder-preset medium
  • H.265: x265 --quality 26 --encoder-preset medium
  • AV1: svt_av1 --quality 30 --encoder-preset 5

Example hardware assisted video encoding options:

  • NVidia NVENC:
    • See HandBrake documentation.
    • HandBrakeOptions:Video: nvenc_h264 --quality 22 --encoder-preset medium
  • Intel QuickSync:
    • See HandBrake documentation.
    • HandBrakeOptions:Video: qsv_h264 --quality 22 --encoder-preset medium

Note that HandBrake is primarily used for video deinterlacing, and only as backup encoder when FFmpeg fails.
The default HandBrakeOptions:Audio configuration is set to copy --audio-fallback ac3 that will copy all supported audio tracks as is, and only encode to ac3 if the audio codec is not natively supported.

Language Matching

Language tag matching supports IETF / RFC 5646 / BCP 47 tag formats as implemented by MkvMerge.
During processing the absence of IETF language tags will treated as a track warning, and an RFC 5646 IETF language will be temporarily assigned based on the ISO639-2B tag.
If ProcessOptions.SetIetfLanguageTags is enabled MkvMerge will be used to remux the file using the --normalize-language-ietf extlang option, see the MkvMerge docs for more details.

Tags are in the form of language-extlang-script-region-variant-extension-privateuse, and matching happens left to right.
E.g. pt will match pt Portuguese, or pt-BR Brazilian Portuguese, or pt-PT European Portuguese.
E.g. pt-BR will only match only pt-BR Brazilian Portuguese.
E.g. zh will match zh Chinese, or zh-Hans simplified Chinese, or zh-Hant for traditional Chinese, and other variants.
E.g. zh-Hans will only match zh-Hans simplified Chinese.

Normalized tags will be expanded for matching.
E.g. cmn-Hant will be expanded to zh-cmn-Hant allowing matching with zh.

See the W3C Language tags in HTML and XML and BCP47 language subtag lookup for more details.

Usage

Use the PlexCleaner --help commandline option to get a list of commands and options.
To get help for a specific command run PlexCleaner <command> --help.

> ./PlexCleaner --help
Description:
  Utility to optimize media files for Direct Play in Plex, Emby, Jellyfin

Usage:
  PlexCleaner [command] [options]

Options:
  --logfile <logfile>  Path to log file
  --logappend          Append to existing log file
  --logwarning         Log warnings and errors only
  --debug              Wait for debugger to attach
  --version            Show version information
  -?, -h, --help       Show help and usage information

Commands:
  defaultsettings   Write default values to settings file
  checkfornewtools  Check for new tool versions and download if newer
  process           Process media files
  monitor           Monitor for file changes and process changed media files
  remux             Re-Multiplex media files
  reencode          Re-Encode media files
  deinterlace       De-Interlace media files
  removesubtitles   Remove subtitles from media files
  createsidecar     Create new sidecar files
  updatesidecar     Update existing sidecar files
  getversioninfo    Print application and tools version information
  getsidecarinfo    Print sidecar file information
  gettagmap         Print media information tag-map
  getmediainfo      Print media information using sidecar files
  gettoolinfo       Print media information using media tools
  createschema      Write settings schema to file

Global Options

Global options apply to all commands.

  • --logfile:
    • Path to the log file.
  • --logappend:
    • Append to the existing log file, default will overwrite the log file.
  • --logwarning:
    • Only log errors and warnings to the log file, default will log all information.
  • --debug:
    • Launch and wait for a debugger to attach.

Process Command

> ./PlexCleaner process --help
Description:
  Process media files

Usage:
  PlexCleaner process [options]

Options:
  --settingsfile <settingsfile> (REQUIRED)  Path to settings file
  --mediafiles <mediafiles> (REQUIRED)      Path to media file or folder
  --parallel                                Enable parallel processing
  --threadcount <threadcount>               Number of threads to use for parallel processing
  --testsnippets                            Create short media clips
  --testnomodify                            Do not make any file modifications
  --reverify                                Re-verify and repair media files in the VerifyFailed state
  --logfile <logfile>                       Path to log file
  --logappend                               Append to existing log file
  --logwarning                              Log warnings and errors only
  --debug                                   Wait for debugger to attach
  -?, -h, --help                            Show help and usage information

The process command will process the media content using options as defined in the settings file and the optional commandline arguments:

  • Delete files with extensions not in the KeepExtensions list.
  • Re-multiplex containers in the ReMuxExtensions list to MKV container format.
  • Remove all tags, titles, thumbnails, cover art, and attachments from the media file.
  • Set IETF language tags and Matroska track flags if missing.
  • Set the language to DefaultLanguage for any track with an undefined language.
  • If multiple audio tracks of the same language but different encoding formats are present, set the default track based on PreferredAudioFormats.
  • Remove tracks with languages not in the KeepLanguages list.
  • Remove duplicate tracks, where duplicates are tracks of the same type and language.
  • Re-multiplex the media file if required.
  • Deinterlace the video track if interlaced.
  • Remove EIA-608 Closed Captions from video streams.
  • Re-encode video if video format matches ReEncodeVideo.
  • Re-encode audio if audio matches the ReEncodeAudioFormats list.
  • Verify the media container and stream integrity, if corrupt try to automatically repair, else conditionally delete the file.

Options:

  • --settingsfile: (required)
    • Path to the settings file.
  • --mediafiles: (required)
    • Path to file or folder containing files to process.
    • Paths with spaces should be double quoted.
    • Repeat the option to include multiple files or directories, e.g. --mediafiles path1 --mediafiles "path with space" --mediafiles file1 --mediafiles file2.
  • --reverify:
    • Re-verify and repair media files that are in the VerifyFailed state.
    • By default files would be skipped due to processing optimization logic when using sidecar files.
  • --parallel:
    • Process multiple files concurrently.
    • When parallel processing is enabled, the default thread count is half the number of system cores.
  • --threadcount:
    • Override the thread count when the --parallel option is enabled.
  • --testsnippets:
    • Create short media clips that limit the processing time required, useful during testing.
  • --testnomodify:
    • Process files but do not make any file modifications, useful during testing.

Example:

./PlexCleaner \
  --logfile PlexCleaner.log \
  process \
  --settingsfile PlexCleaner.json \
  --parallel \
  --mediafiles "C:\Foo With Space\Test.mkv" \
  --mediafiles D:\Media

Re-Multiplex, Re-Encode, De-Interlace, Remove Subtitles Commands

These commands have no conditional logic and will process all specified media files.

  • remux:
    • Re-multiplex the media files using MkvMerge.
    • Useful to update the file with the latest multiplexer.
  • reencode:
    • Re-encode the media files using FFmpeg.
  • deinterlace:
    • De-interlace interlaced media files using HandBrake.
  • removesubtitles:
    • Remove all subtitle tracks from the media files.
    • Useful when subtitles are forced and contains offensive language or advertising.

Monitor

  • monitor:
    • Watch the specified folders for file changes, and periodically run the process command on the changed folders.
    • The monitor command honors the process options.
    • Note that the FileSystemWatcher used to monitor for changes may not always work as expected when changes are made via virtual or network filesystem, e.g. NFS or SMB backed volumes may not detect changes made directly to the underlying ZFS filesystem.

Create and Update Sidecar Files

  • createsidecar:
    • Create or overwrite and re-create sidecar files.
    • All existing state attributes will be deleted.
  • updatesidecar:
    • Update the existing sidecar with current media tool information.
    • Existing state attributes will be retained unless the media file had been modified.

Get Information

  • gettagmap:
    • Calculate and print media file attribute mappings between between different media tools.
  • getmediainfo:
    • Print media attribute information using the Sidecar file if present.
    • If sidecar is not present or out of date media tools will be used.
  • gettoolinfo:
    • Print media attribute information using the current media tools.
  • getsidecarinfo:
    • Print sidecar file attribute information.
  • getversioninfo:
    • Print application version, runtime version, and media tools version information.

3rd Party Tools

Sample Media Files


plexcleaner's People

Contributors

aseques avatar dependabot[bot] avatar ptr727 avatar ptrsmntc avatar richlander avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

plexcleaner's Issues

Distinguish between Chinese languages

The "chi" language tag is used for different types of written Chinese, figure out a way to specify the sub-types.

4/27/2020 1:22:10 PM : Keep : Subtitle : MuxingMode : , Forced : False, Track : Format : SubRip/SRT, Codec : S_TEXT/UTF8, Language : chi, Id : 5, Number : 6, State : Keep, Title : Simplified Chinese
4/27/2020 1:22:11 PM : Remove : Subtitle : MuxingMode : , Forced : False, Track : Format : SubRip/SRT, Codec : S_TEXT/UTF8, Language : chi, Id : 6, Number : 7, State : Remove, Title : Traditional Chinese, Default : False
4/27/2020 1:22:11 PM : Remove : Subtitle : MuxingMode : , Forced : False, Track : Format : SubRip/SRT, Codec : S_TEXT/UTF8, Language : chi, Id : 7, Number : 8, State : Remove, Title : (Yue Chinese), Default : False

Move test flags from JSON to commandline

Move test flags to commandline options.
Too easy to forget to reset the flag and modify production content.

    // Create short video clips, useful during testing
    // Note the media files will be overwritten with short clips
    "TestSnippets": false

  "ProcessOptions": {
    // Do not make any modifications, useful during testing
    "TestNoModify": false,

alpine: mediainfo not found

Is this a new issue that can be reproduced?

  • This is a new issue that can be reproduced.

Which operating systems reproduce the issue?

  • Windows
  • Docker
  • Other

Version information.

OS Version: Synology DSM 6
Docker Version: Docker version 20.10.3, build b35e731
Docker Image: alpine
PlexCleaner getversioninfo: 3.2.31

Steps to reproduce?

Steps to reproduce:

  • install alpine branch
  • run config
  • [ERR] <1> MediaInfo not found : "mediainfo"

Expectation:

  • docker should include all required tools

Commandline.

/ # /PlexCleaner/PlexCleaner \
>   --logfile /media/PlexCleaner/PlexCleaner.log \
>   process \
>   --settingsfile /media/PlexCleaner/PlexCleaner.json \
>   --mediafiles /media/Movies \
>   --mediafiles /media/TV

Relevant log output.

Press Ctrl+C or Ctrl+Z or Ctrl+Q to exit.
22:11:25 [INF] <1> Loading settings from : "/media/PlexCleaner/PlexCleaner.json"
22:11:26 [INF] <1> Logging output to : "/media/PlexCleaner/PlexCleaner.log"
22:11:26 [INF] <1> Application Version : "PlexCleaner : 3.2.31+154c388a24 (Release)", Runtime Version : "7.0.8"
22:11:26 [INF] <1> Parallel Processing: False : Thread Count: 1, Processor Count: 2
22:11:26 [INF] <1> Executing FfMpeg : "-version"
22:11:26 [INF] <1> FfMpeg : Version: "6.0", Path: "ffmpeg"
22:11:26 [INF] <1> Executing FfProbe : "-version"
22:11:26 [INF] <1> FfProbe : Version: "6.0", Path: "ffprobe"
22:11:26 [INF] <1> Executing MkvMerge : "--version"
22:11:26 [INF] <1> MkvMerge : Version: "78.0", Path: "mkvmerge"
22:11:26 [INF] <1> Executing MkvPropEdit : "--version"
22:11:26 [INF] <1> MkvPropEdit : Version: "78.0", Path: "mkvpropedit"
22:11:26 [INF] <1> Executing MkvExtract : "--version"
22:11:27 [INF] <1> MkvExtract : Version: "78.0", Path: "mkvextract"
22:11:27 [INF] <1> Executing MediaInfo : "--version"
22:11:27 [ERR] <1> MediaInfo not found : "mediainfo"
22:11:27 [INF] <1> Exit Code : 1

Settings file.

{
  "$schema": "https://raw.githubusercontent.com/ptr727/PlexCleaner/main/PlexCleaner.schema.json",
  "SchemaVersion": 3,
  "ToolsOptions": {
    "UseSystem": true,
    "RootPath": "",
    "RootRelative": false,
    "AutoUpdate": false
  },
  "ProcessOptions": {
    "KeepOriginalLanguage": true,
    "SetIetfLanguageTags": true,
    "SetTrackFlags": true,
    "SetUnknownLanguage": true,
    "DefaultLanguage": "en",
    "RemoveUnwantedLanguageTracks": false,
    "RemoveDuplicateTracks": false,
    "RemoveTags": true,
    "UseSidecarFiles": true,
    "SidecarUpdateOnToolChange": false,
    "Verify": true,
    "RestoreFileTimestamp": false,
    "FileIgnoreList": []
  },
  "ConvertOptions": {
    "FfMpegOptions": {
      "Video": "libx264 -crf 22 -preset medium",
      "Audio": "ac3",
      "Global": "-analyzeduration 2147483647 -probesize 2147483647",
      "Output": "-max_muxing_queue_size 1024 -abort_on empty_output"
    },
    "HandBrakeOptions": {
      "Video": "x264 --quality 22 --encoder-preset medium",
      "Audio": "copy --audio-fallback ac3"
    }
  },
  "VerifyOptions": {
    "AutoRepair": true,
    "DeleteInvalidFiles": false,
    "RegisterInvalidFiles": false,
    "MaximumBitrate": 100000000
  },
  "MonitorOptions": {
    "MonitorWaitTime": 60,
    "FileRetryWaitTime": 5,
    "FileRetryCount": 2
  }
}

Log file.

No response

Media file information.

No response

Workaround

  • use debian

Retain original creation date

The newly created video files all have the creation and modification timestamp of today. This messes up my photo's collection. Would it be possible to add a flag that causes PlexCleaner to copy the original dates?

"Assertion failed" as soon as it encounters an .SRT

Log:
https://pastebin.com/raw/7G42Pii7
Docker Stack:

version: '3.3'
services:
    plexcleaner:
        image: ptr727/plexcleaner
        container_name: plexcleaner
        environment:
          - PUID=1000
          - PGID=100
          - TZ=Europe/Oslo
        command: /PlexCleaner/PlexCleaner --settingsfile /config/PlexCleaner.json process --mediafiles /DATA00/media
        volumes:
          - /srv/dev-disk-by-label-DATA01/Docker_Config/PLEXCLEANER:/config
          - /srv/dev-disk-by-label-DATA00:/DATA00/media:rw

PlexCleaner.json:

{
  "SchemaVersion": 1,
  "ToolsOptions": {
    "UseSystem": false,
    "RootPath": ".\\Tools\\",
    "RootRelative": true,
    "AutoUpdate": true
  },
  "ConvertOptions": {
    "EnableH265Encoder": false,
    "VideoEncodeQuality": 20,
    "AudioEncodeCodec": "aac"
  },
  "ProcessOptions": {
    "DeleteEmptyFolders": true,
    "DeleteUnwantedExtensions": false,
    "KeepExtensions": ".partial~",
    "ReMux": false,
    "ReMuxExtensions": ".avi,.m2ts,.ts,.vob,.mp4,.m4v,.asf,.wmv",
    "DeInterlace": true,
    "ReEncode": false,
    "ReEncodeVideoFormats": "mpeg2video,mpeg4,msmpeg4v3,msmpeg4v2,vc1,h264",
    "ReEncodeVideoCodecs": "*,dx50,div3,mp42,*,*",
    "ReEncodeVideoProfiles": "*,*,*,*,*,Constrained Baseline@30",
    "ReEncodeAudioFormats": "flac,mp2,vorbis,wmapro,pcm_s16le",
    "SetUnknownLanguage": false,
    "DefaultLanguage": "eng",
    "RemoveUnwantedLanguageTracks": true,
    "KeepLanguages": "eng,nor,swe,dan",
    "RemoveDuplicateTracks": true,
    "PreferredAudioFormats": "truehd atmos,truehd,dts-hd master audio,dts-hd high resolution audio,dts,e-ac-3,ac-3",
    "RemoveTags": true,
    "UseSidecarFiles": true,
    "SidecarUpdateOnToolChange": false,
    "Verify": false,
    "FileIgnoreList": []
  },
  "MonitorOptions": {
    "MonitorWaitTime": 60,
    "FileRetryWaitTime": 5,
    "FileRetryCount": 2
  },
  "VerifyOptions": {
    "AutoRepair": true,
    "DeleteInvalidFiles": false,
    "RegisterInvalidFiles": true,
    "MinimumDuration": 300,
    "VerifyDuration": 0,
    "IdetDuration": 0,
    "MaximumBitrate": 100000000,
    "MinimumFileAge": 0
  }
}

FFmpeg removes IETF language tags

FFmpeg removes IETF BCP-47 language tags from MKV files during remuxing or encoding.

See FFmpeg Trac issue ticket.

See Matroska IETF Draft Spec
See Languages in Matroska and MKVToolNix WiKi
See Matroska EBML LanguageIETF tag

Summary: When FFmpeg creates MKV files from MKV files, the LanguageIETF tags from the original file is not written, and the language granularity is lost.

Create media file snippet: mkvmerge --split parts:00:00:00-00:01:00 --output MKV-IETF-Snippet.mkv MKV-IETF.mkv

MkvMerge: mkvmerge --identify MKV-IETF-Snippet.mkv --identification-format json

  • "language": "eng", "language_ietf": "en"
  • "language": "spa", "language_ietf": "es-ES"
  • "language": "srp", "language_ietf": "sr-Latn-RS"

MediaInfo: mediainfo --Output=XML MKV-IETF-Snippet.mkv

  • <Language>en</Language>
  • <Language>es-ES</Language>
  • <Language>sr-Latn-RS</Language>

FfProbe: ffprobe -loglevel quiet -show_streams -show_format -print_format json MKV-IETF-Snippet.mkv

  • "language": "eng"
  • "language": "spa"
  • "language": "srp"

ReMux using FfMpeg: ffmpeg -i MKV-IETF-Snippet.mkv -map 0 -codec copy -f matroska MKV-IETF-Snippet-FfMpeg.mkv

MkvMerge differences:

  • "language_ietf", ``: "en": Removed the IETF language tag
  • "language_ietf", ``: "es-ES": Removed the IETF language tag
  • "language_ietf", ``: "sr-Latn-RS": Removed the IETF language tag

MedaInfo difference:

  • <Default>No</Default>, <Default>Yes</Default>: Track changed from not default to default
  • <Language>en-US</Language>, <Language>en</Language>: Removed the IETF language tag granularity
  • <Language>es-ES</Language>, <Language>es</Language>: Removed the IETF language tag granularity
  • <Language>sr-Latn-RS</Language>, <Language>sr</Language>: Removed the IETF language tag granularity

FfProbe differences:

  • "default": 0, "default": 1: Changed track from not default to default

Encode mono to stereo

Some of my old video files have a mono channel that is only played in the left ear. Would it be possible to

  • map the mono input channel to a stereo output
  • copy the mono channel to L and R

Handbrake PPA does not support Ubuntu Jammy

Docker using ubuntu:latest tag switched from Focal to Jammy in April.
Handbrake PPA does not currently support Jammy:
The repository 'https://ppa.launchpadcontent.net/stebbins/handbrake-releases/ubuntu jammy Release' does not have a Release file

Reverting to using ubuntu:focal in Docker builds.

Reported here, currently unresolved.

FFprobe closed_captions JSON tag not set

ffprobe does not identify closed captions when using JSON output mode.

Unformatted output:

./ffprobe.exe D:\Temp\CC.mkv
  Stream #0:0(eng): Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080, Closed Captions, SAR 1:1 DAR 16:9, 29.97 fps, 29.97 tbr, 1k tbn (default)

Note the Closed Captions attribute.

JSON output:

./ffprobe.exe -loglevel quiet -print_format json -show_streams -show_format D:\Temp\CC.mkv
{
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
...
            "closed_captions": 0,

Note the closed_captions attribute is 0, expect it to be 1.

Asked for help or alternatives here:
https://www.reddit.com/r/ffmpeg/comments/tcnhto/how_to_detect_closed_captions_in_video_stream/
https://forum.videohelp.com/threads/405123-Detect-embedded-closed-captions-in-video-stream-using-ffprobe-json-output

Discovered an abandoned patch for exactly this issue, seems there was some internal disagreement:
https://patchwork.ffmpeg.org/project/ffmpeg/patch/MN2PR04MB59815313285AA685E37D09AEBAB09@MN2PR04MB5981.namprd04.prod.outlook.com/
https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=&submitter=&state=*&q=closed_captions&archive=both&delegate=
https://www.mail-archive.com/[email protected]/msg126211.html

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 90e895bbf9..f5c6335a13 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -2655,9 +2655,9 @@  static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
         if (dec_ctx) {
             print_int("coded_width",  dec_ctx->coded_width);
             print_int("coded_height", dec_ctx->coded_height);
-            print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));
-            print_int("film_grain", !!(dec_ctx->properties & FF_CODEC_PROPERTY_FILM_GRAIN));
         }
+        print_int("closed_captions", !!(par->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));
+        print_int("film_grain", !!(par->properties & FF_CODEC_PROPERTY_FILM_GRAIN));
         print_int("has_b_frames", par->video_delay);
         sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
         if (sar.num) {

Source related to closed_captions setting:
https://github.com/FFmpeg/FFmpeg/blob/b8e58f0858116ac102fc116ce1bdf6727df1eb0c/libavcodec/avcodec.c#L650
https://github.com/FFmpeg/FFmpeg/blob/316e0ff752c782439843cc63d0eb8b9c998e47de/fftools/ffprobe.c#L2902

My request to the ffmpeg-devel list to reconsider:
https://www.mail-archive.com/[email protected]/msg133559.html

MkvToolJsonSchema Failed to lookup ISO639 Language from IETF LanguageIetf

Error on file

16:04:08 [WRN] <11> MkvToolJsonSchema : Failed to lookup ISO639 Language from IETF LanguageIetf : "cpe" !-> "cpe"

https://www.loc.gov/standards/iso639-2/php/code_list.php

looking at cpe its a english language and the video file with cpe plays in english

PlexCleaner.json

{
  "$schema": "https://raw.githubusercontent.com/ptr727/PlexCleaner/develop/PlexCleaner.schema.json",
  "SchemaVersion": 3,
  "ToolsOptions": {
    "UseSystem": false,
    "RootPath": ".\\Tools\\",
    "RootRelative": true,
    "AutoUpdate": false
  },
  "ProcessOptions": {
    "KeepOriginalLanguage": true,
    "RemoveClosedCaptions": true,
    "SetIetfLanguageTags": true,
    "SetTrackFlags": true,
    "KeepExtensions": [
      ".partial~",
      ".nfo",
      ".jpg",
      ".srt",
      ".smi",
      ".ssa",
      ".ass",
      ".vtt",
      ".mp3"
    ],
    "ReMuxExtensions": [
      ".avi",
      ".mxf",
      ".m2p",
      ".ps",
      ".m2ts",
      ".mts",
      ".ts",
      ".tsv",
      ".vob",
      ".evo",
      ".3gp",
      ".3g2",
      ".f4v",
      ".flv",
      ".mp4",
      ".m4v",
      ".asf",
      ".wmv",
      ".dv",
      ".mov",
      ".qt",
      ".ogg",
      ".ogv",
      ".ogx",
      ".webm",
      ".rmvb",
      ".divx"
    ],
    "ReEncodeVideo": [
      {
        "Format": "mpeg2video"
      },
      {
        "Format": "vc1"
      },
      {
        "Format": "wmv3"
      },
      {
        "Format": "msrle"
      },
      {
        "Format": "rawvideo"
      },
      {
        "Format": "indeo5"
      },
      {
        "Format": "h264",
        "Profile": "Constrained Baseline@30"
      },
      {
        "Format": "mpeg4",
        "Codec": "dx50"
      },
      {
        "Format": "msmpeg4v2",
        "Codec": "mp42"
      },
      {
        "Format": "msmpeg4v3",
        "Codec": "div3"
      }
    ],
    "ReEncodeAudioFormats": [
      "flac",
      "mp2",
      "vorbis",
      "wmapro",
      "opus",
      "wmav2",
      "adpcm_ms",
      "pcm_u8",
      "pcm_s16le"
    ],
    "KeepLanguages": [
      "en",
      "cpe"
    ],
    "PreferredAudioFormats": [
      "truehd atmos",
      "truehd",
      "dts-hd master audio",
      "dts-hd high resolution audio",
      "dts",
      "e-ac-3",
      "ac-3"
    ],
    "DeleteEmptyFolders": true,
    "DeleteUnwantedExtensions": true,
    "ReMux": true,
    "DeInterlace": true,
    "ReEncode": true,
    "SetUnknownLanguage": true,
    "DefaultLanguage": "en",
    "RemoveUnwantedLanguageTracks": true,
    "RemoveDuplicateTracks": true,
    "RemoveTags": true,
    "UseSidecarFiles": true,
    "SidecarUpdateOnToolChange": false,
    "Verify": true,
    "RestoreFileTimestamp": false,
    "FileIgnoreList": []
  },
  "ConvertOptions": {
    "FfMpegOptions": {
      "Video": "h264_nvenc -crf 20 -preset medium",
      "Audio": "ac3",
      "Global": "-analyzeduration 2147483647 -probesize 2147483647 -hwaccel cuda -hwaccel_output_format cuda",
      "Output": "-max_muxing_queue_size 1024 -abort_on empty_output"
    },
    "HandBrakeOptions": {
      "Video": "nvenc_h264 --quality 20 --encoder-preset medium",
      "Audio": "copy --audio-fallback ac3"
    }
  },
  "VerifyOptions": {
    "AutoRepair": true,
    "DeleteInvalidFiles": false,
    "RegisterInvalidFiles": false,
    "MinimumDuration": 300,
    "VerifyDuration": 0,
    "IdetDuration": 0,
    "MaximumBitrate": 100000000,
    "MinimumFileAge": 0
  },
  "MonitorOptions": {
    "MonitorWaitTime": 60,
    "FileRetryWaitTime": 5,
    "FileRetryCount": 2
  }
}

I added cpe to the keep languages with english eng etc its a odd one because cpe is a english language but rather than rename it to en or eng it looks like its renaming it from cpe to cpe

Crash on no audio stream

Some of my video files don't have an audio channel. This causes PlexCleaner to crash. I've noticed this with the MJPEG codec (AVI, wmv). Not sure about other codecs.

The First() call throws an error:

bitrateInfo.Calculate(packetList,
FfProbeInfo.Video.First().Id,
FfProbeInfo.Audio.First().Id,
Program.Config.VerifyOptions.MaximumBitrate / 8);

Unhandled exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.InvalidOperationException: Sequence contains no elements
   at System.Linq.ThrowHelper.ThrowNoElementsException()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at PlexCleaner.ProcessFile.GetBitrateInfo(BitrateInfo& bitrateInfo) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\ProcessFile.cs:line 1013
   at PlexCleaner.ProcessFile.VerifyBitrate() in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\ProcessFile.cs:line 623
   at PlexCleaner.ProcessFile.Verify(Boolean conditional, Boolean& modified) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\ProcessFile.cs:line 542
   at PlexCleaner.Process.ProcessFile(FileInfo fileinfo, Boolean& modified, States& state, FileInfo& processInfo) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\Process.cs:line 268
   at PlexCleaner.Process.<>c__DisplayClass3_0.<ProcessFiles>b__0(FileInfo fileInfo) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\Process.cs:line 114
   at PlexCleaner.Process.ProcessFilesDriver(List`1 fileList, String taskName, Func`2 taskFunc) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\Process.cs:line 542
   at PlexCleaner.Process.ProcessFiles(List`1 fileList) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\Process.cs:line 111
   at PlexCleaner.Program.ProcessCommand(CommandLineOptions options) in D:\a\PlexCleaner\PlexCleaner\PlexCleaner\Program.cs:line 109
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Delegate.DynamicInvoke(Object[] args)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.InvokeAsync(InvocationContext context)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseParseErrorReporting>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass15_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass26_0.<<UseVersionOption>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass24_0.<<UseTypoCorrections>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__23_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass21_0.<<UseParseDirective>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseDebugDirective>b__8_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__7_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass11_0.<<UseExceptionHandler>b__0>d.MoveNext()

HandBrake removes IETF language tags

HandBrake removes IETF BCP-47 language tags from MKV files during encoding.

See related FFmpeg issue ticket for a similar problem.

See HandBrake forum post, I could not create a HandBrake GitHub issue.
See related HandBrake GUI issue

See Matroska IETF Draft Spec
See Languages in Matroska and MKVToolNix WiKi
See Matroska EBML LanguageIETF tag

Summary: When HandBrake creates MKV files from MKV files, the LanguageIETF tags from the original file is not written, and the language granularity is lost.

Create media file snippet: mkvmerge --split parts:00:00:00-00:01:00 --output MKV-IETF-Snippet.mkv MKV-IETF.mkv

MkvMerge: mkvmerge --identify MKV-IETF-Snippet.mkv --identification-format json

  • "language": "eng", "language_ietf": "en"
  • "language": "spa", "language_ietf": "es-ES"
  • "language": "srp", "language_ietf": "sr-Latn-RS"

MediaInfo: mediainfo --Output=XML MKV-IETF-Snippet.mkv

  • <Language>en</Language>
  • <Language>es-ES</Language>
  • <Language>sr-Latn-RS</Language>

Encode using HandBrake: HandBrakeCLI --input MKV-IETF-Snippet.mkv --output MKV-IETF-Snippet-HandBrake.mkv --format av_mkv --encoder x264 --quality 22 --encoder-preset medium --all-audio --aencoder copy --audio-fallback ac3 --all-subtitles

Notice that some of the extended languages are not recognized in the console output:

[20:00:40]  * subtitle track 1, English [UTF-8] (track 0, id 0x2, Text) -> Passthrough
[20:00:40]  * subtitle track 2, English [UTF-8] (track 1, id 0x3, Text) -> Passthrough
[20:00:40]    + name: SDH
[20:00:40]  * subtitle track 3, ????????? [UTF-8] (track 2, id 0x4, Text) -> Passthrough
[20:00:40]  * subtitle track 4, cestina [UTF-8] (track 3, id 0x5, Text) -> Passthrough
[20:00:40]  * subtitle track 5, dansk [UTF-8] (track 4, id 0x6, Text) -> Passthrough
[20:00:40]  * subtitle track 6, espaรฑol [UTF-8] (track 5, id 0x7, Text) -> Passthrough
[20:00:40]    + name: Spanish (Latin America)
[20:00:40]  * subtitle track 7, espaรฑol [UTF-8] (track 6, id 0x8, Text) -> Passthrough
[20:00:40]    + name: Spanish (Latin America) (SDH)
[20:00:40]  * subtitle track 8, espaรฑol [UTF-8] (track 7, id 0x9, Text) -> Passthrough
[20:00:40]    + name: Spanish (Spain)
[20:00:40]  * subtitle track 9, suomi [UTF-8] (track 8, id 0xa, Text) -> Passthrough
[20:00:40]  * subtitle track 10, hrvatski [UTF-8] (track 9, id 0xb, Text) -> Passthrough
[20:00:40]  * subtitle track 11, magyar [UTF-8] (track 10, id 0xc, Text) -> Passthrough
[20:00:40]  * subtitle track 12, ?????????? [UTF-8] (track 11, id 0xd, Text) -> Passthrough
[20:00:40]  * subtitle track 13, Nederlands [UTF-8] (track 12, id 0xe, Text) -> Passthrough
[20:00:40]  * subtitle track 14, norsk [UTF-8] (track 13, id 0xf, Text) -> Passthrough
[20:00:40]  * subtitle track 15, polski [UTF-8] (track 14, id 0x10, Text) -> Passthrough
[20:00:40]  * subtitle track 16, Portugues [UTF-8] (track 15, id 0x11, Text) -> Passthrough
[20:00:40]  * subtitle track 17, romรขna [UTF-8] (track 16, id 0x12, Text) -> Passthrough
[20:00:40]  * subtitle track 18, slovenscina [UTF-8] (track 17, id 0x13, Text) -> Passthrough
[20:00:40]  * subtitle track 19, srpski [UTF-8] (track 18, id 0x14, Text) -> Passthrough
[20:00:40]  * subtitle track 20, svenska [UTF-8] (track 19, id 0x15, Text) -> Passthrough

MkvMerge --identify differences:

  • "language_ietf", ``: "en": Removed the IETF language tag
  • "language_ietf", ``: "es-ES": Removed the IETF language tag
  • "language_ietf", ``: "sr-Latn-RS": Removed the IETF language tag

Tested using master:

> ./HandBrakeCLI --version
[20:06:57] Compile-time hardening features are enabled
[20:06:57] qsv: is available on this system
Cannot load nvEncodeAPI64.dll
[20:06:57] vcn: not available on this system
[20:06:57] hb_init: starting libhb thread
[20:06:57] thread 1 started ("libhb")
HandBrake 20230329184118-13ae00bdf-master

HandBrake has exited.

Add support for hardware accelerated GPU encoding

Add support for hardware accelerated GPU encoding, e.g. NVidia Cuda, Intel QuickSync, etc.

See:
https://trac.ffmpeg.org/wiki/HWAccelIntro
https://handbrake.fr/docs/en/latest/technical/video-nvenc.html
https://handbrake.fr/docs/en/latest/technical/video-qsv.html
https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/
https://arstech.net/ffmpeg-gpu-transcoding-examples/
https://superuser.com/questions/1296374/best-settings-for-ffmpeg-with-nvenc

The code will need refactoring as the FFmpeg and Handbrake commandline options are dynamically generated, and for e.g. ffmpeg both the global and encoder options need to be set.

An option is to remove the discrete options for H264/265, quality, and audio codec should be removed and the user allowed to construct their own commandline in the JSON configuration, thus allowing for custom configurations.

HanbrakeCLI PPA provided by stebbins is no longer maintained

GitHub action builds started failing around 19 June 2022.
Issues is that the John Stebbins PPA for Handbrake is no longer being maintained, no longer available.

Old way of installing by PPA:
https://handbrake.fr/docs/en/1.0.0/get-handbrake/where-to-get-handbrake.html
https://launchpad.net/~stebbins
https://launchpad.net/~stebbins/+archive/ubuntu/handbrake-snapshots

New way of installing by flatpak:
https://handbrake.fr/docs/en/1.5.0/get-handbrake/download-and-install.html

But flatpak install requires different CLI command: flatpak run fr.handbrake.HandBrakeCLI vs. HandBrakeCLI

Figure out how to install from alternate PPA, or how to install from flatpak and launch using flatpak, or maybe compile from code.

Remux with keep logic is flawed in case of tool failure

In public static bool Convert::ReMuxToMkv(string inputname, MediaInfo keep, out string outputname)
On error in one of the tools, when keep is not null, the mediainfo type must match the converter type of hte other tool.
E.g. if an IO error occurs during MKV remux, FfMpeg remux will fail because keep is not null and media type is not FfMpeg.

Tools folder or 7-Zip does not exist

C:\PlexCleaner>PlexCleaner.exe --settings PlexCleaner.json checkfornewtools
4/2/2020 10:42:26 PM : Loading settings from : "PlexCleaner.json"
4/2/2020 10:42:26 PM : Tools folder or 7-Zip does not exist : "C:\PlexCleaner\Tools"

I have the folder Tools created there and have a 7Zip folder in their as well.

Refactor codec encoding options

// Re-encode the video if the format, codec, and profile values match
// * will match anything, the number of filter entries must match
// Use FFProbe attribute naming, and the `printmediainfo` command to get media info
"ReEncodeVideoFormats": "mpeg2video,mpeg4,msmpeg4v3,msmpeg4v2,vc1,h264,wmv3",
"ReEncodeVideoCodecs": "*,dx50,div3,mp42,*,*,*",
"ReEncodeVideoProfiles": "*,*,*,*,*,Constrained Baseline@30,*",
// Re-encode matching audio codecs
// If the video format is not H264 or H265, video will automatically be converted to H264 to avoid audio sync issues
// Use FFProbe attribute naming, and the `printmediainfo` command to get media info
"ReEncodeAudioFormats": "flac,mp2,vorbis,wmapro,pcm_s16le,opus,wmav2",

Use JSON array instead of comma delimited strings.
Add wildcard matching to codecs, e.g. *pcm to match any pcm format.

Not Observing Optimizations on x264 to x265 (HEVC)

I'm running the latest version via docker (v2.10.7) and wired PlexCleaner up to sabnzbd to process as a post-processing script.

I have noticed that with the default JSON config, even when I have an x264 file get processed, it basically doesn't do anything in terms of compression when I execute plexcleaner against it (same file size, not much discernable difference).

Here is an output of a recent file (it was an x264 1080p file, ~4.4GB file)

--------------
docker run --rm -v /media/tower/Storage/Completed/_tv/tv.show.S11E23.1080p.WEB.H264-CAKES:/clean:rw -v /opt/plexcleaner:/config ptr727/plexcleaner /PlexCleaner/PlexCleaner --settingsfile /config/PlexCleaner.json --logfile /config/PlexCleaner.log process --mediafiles /clean --parallel --threadcount 10
0 15:54:42 [INF] <1> Loading settings from : "/config/PlexCleaner.json"
15:54:43 [INF] <1> Logging output to : "/config/PlexCleaner.log"
15:54:43 [INF] <1> Application Version : "2.10.7+727e8e2131.727e8e21317b32c7d9c1d9675f11dfe2fba26f47", Runtime Version : "6.0.10"
15:54:43 [INF] <1> Parallel Processing: True : Thread Count: 10, Processor Count: 20
15:54:43 [INF] <1> Executing FfMpeg : "-version"
15:54:43 [INF] <1> FfMpeg : Version: "5.1.2", Path: "ffmpeg"
15:54:43 [INF] <1> Executing FfProbe : "-version"
15:54:43 [INF] <1> FfProbe : Version: "5.1.2", Path: "ffprobe"
15:54:43 [INF] <1> Executing MkvMerge : "--version"
15:54:43 [INF] <1> MkvMerge : Version: "71.1.0", Path: "mkvmerge"
15:54:43 [INF] <1> Executing MkvPropEdit : "--version"
15:54:43 [INF] <1> MkvPropEdit : Version: "71.1.0", Path: "mkvpropedit"
15:54:43 [INF] <1> Executing MkvExtract : "--version"
15:54:43 [INF] <1> MkvExtract : Version: "71.1.0", Path: "mkvextract"
15:54:43 [INF] <1> Executing MediaInfo : "--version"
15:54:43 [INF] <1> MediaInfo : Version: "22.09", Path: "mediainfo"
15:54:43 [INF] <1> Executing HandBrake : "--version"
15:54:43 [INF] <1> HandBrake : Version: "1.5.1", Path: "HandBrakeCLI"
15:54:43 [INF] <1> Executing SevenZip : ""
15:54:43 [INF] <1> SevenZip : Version: "16.02", Path: "7z"
15:54:43 [INF] <1> Creating file and folder list ...
15:54:43 [INF] <9> Enumerating files in "/clean" ...
15:54:43 [INF] <1> Discovered 1 files from 1 directories
15:54:43 [INF] <1> Process Options: TestSnippets: False, TestNoModify: False, ReProcess: 0, ReVerify: False, FileIgnoreList: 0
15:54:43 [INF] <1> Starting "Process", processing 1 files ...
15:54:43 [INF] <13> "Process" (0.00%) Before : "/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv"
15:54:43 [INF] <13> Reading media info from tools : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
15:54:43 [INF] <13> Executing MediaInfo : "--Output=XML \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
15:54:44 [INF] <13> Executing MkvMerge : "--identify \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" --identification-format json"
15:54:44 [INF] <13> Executing FfProbe : "-loglevel quiet -show_streams -show_format -print_format json \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
15:54:45 [INF] <13> "MediaInfo" : Type: "VideoInfo", Format: "AVC", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 1, Number: 0, Title: "", Default: True, Profile: "High@4", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "MediaInfo" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 2, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "MediaInfo" : Type: "SubtitleInfo", Format: "UTF-8", Codec: "S_TEXT/UTF8", Language: "eng", Id: 3, Number: 2, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
15:54:45 [INF] <13> "MkvMerge" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "MkvMerge" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "MkvMerge" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
15:54:45 [INF] <13> "FfProbe" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "und", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "FfProbe" : Type: "AudioInfo", Format: "eac3", Codec: "ATSC A/52B (AC-3, E-AC-3)", Language: "eng", Id: 1, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
15:54:45 [INF] <13> "FfProbe" : Type: "SubtitleInfo", Format: "subrip", Codec: "SubRip subtitle", Language: "eng", Id: 2, Number: 2, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
15:54:45 [INF] <13> Sidecar created : State: None : "tv.show.s11e23.1080p.web.h264-cakes.PlexCleaner"
15:54:45 [INF] <13> Finding Closed Captions in video stream : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
15:54:45 [INF] <13> Executing FfProbe : "-hide_banner \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
15:54:45 [INF] <13> Counting interlaced frames : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
15:54:45 [INF] <13> Executing FfMpeg : "-analyzeduration 2147483647 -probesize 2147483647 -i \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" -max_muxing_queue_size 1024 -abort_on empty_output -hide_banner -nostats -hide_banner -nostats -xerror -filter:v idet -an -f rawvideo -y /dev/null"
16:08:57 [INF] <13> FfMpeg Idet: Interlaced: False (0.13 % > 5.00 %), Interlaced: 195, Progressive: 144256, Undetermined: 2543, Total: 146994 : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:08:57 [INF] <13> Setting unknown language tracks to "eng" : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:08:57 [INF] <13> "Known" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:08:57 [INF] <13> "Known" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
16:08:57 [INF] <13> "Unknown" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:08:57 [INF] <13> Executing MkvPropEdit : "\"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" --flush-on-close --edit track:@1 --set language=eng"
16:08:57 [INF] <13> Waiting for IO to flush : 5s : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:09:02 [INF] <13> Reading media info from tools : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:09:02 [INF] <13> Executing MediaInfo : "--Output=XML \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
16:09:11 [INF] <13> Executing MkvMerge : "--identify \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" --identification-format json"
16:09:11 [INF] <13> Executing FfProbe : "-loglevel quiet -show_streams -show_format -print_format json \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
16:09:11 [INF] <13> "MediaInfo" : Type: "VideoInfo", Format: "AVC", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "eng", Id: 1, Number: 0, Title: "", Default: True, Profile: "High@4", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "MediaInfo" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 2, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "MediaInfo" : Type: "SubtitleInfo", Format: "UTF-8", Codec: "S_TEXT/UTF8", Language: "eng", Id: 3, Number: 2, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
16:09:11 [INF] <13> "MkvMerge" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "eng", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "MkvMerge" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "MkvMerge" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
16:09:11 [INF] <13> "FfProbe" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "eng", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "FfProbe" : Type: "AudioInfo", Format: "eac3", Codec: "ATSC A/52B (AC-3, E-AC-3)", Language: "eng", Id: 1, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:09:11 [INF] <13> "FfProbe" : Type: "SubtitleInfo", Format: "subrip", Codec: "SubRip subtitle", Language: "eng", Id: 2, Number: 2, Title: "English [SDH]", Default: False, Forced: False, State: None, HasErrors: False, HasTags: True
16:09:11 [INF] <13> Sidecar updated : State: SetLanguage : "tv.show.s11e23.1080p.web.h264-cakes.PlexCleaner"
16:09:11 [INF] <13> Calculating bitrate info : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:09:11 [INF] <13> Executing FfProbe : "-loglevel error -show_packets -show_entries packet=codec_type,stream_index,pts_time,dts_time,duration_time,size -print_format json \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
16:12:47 [INF] <13> "Video" : Length: 00:51:03, Minimum: "8Kbps", Maximum: "23.100Mbps", Average: "11.100Mbps", Exceeded: 0, Duration: 00:00:00
16:12:47 [INF] <13> "Audio" : Length: 00:51:03, Minimum: "266.200Kbps", Maximum: "655.400Kbps", Average: "639.900Kbps", Exceeded: 0, Duration: 00:00:00
16:12:47 [INF] <13> "Combined" : Length: 00:51:03, Minimum: "274.200Kbps", Maximum: "23.700Mbps", Average: "11.800Mbps", Exceeded: 0, Duration: 00:00:00
16:12:47 [INF] <13> Verifying media streams : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:12:47 [INF] <13> Executing FfMpeg : "-analyzeduration 2147483647 -probesize 2147483647 -i \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" -max_muxing_queue_size 1024 -abort_on empty_output -hide_banner -nostats -hide_banner -nostats -loglevel error -xerror -f null -"
16:19:02 [INF] <13> Sidecar updated : State: SetLanguage, Verified : "tv.show.s11e23.1080p.web.h264-cakes.PlexCleaner"
16:19:02 [INF] <13> Clearing all tags from media file : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:19:02 [INF] <13> Executing MkvPropEdit : "\"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" --flush-on-close --tags all: --delete title --edit track:@3 --delete name"
16:19:03 [INF] <13> Waiting for IO to flush : 5s : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:19:08 [INF] <13> Reading media info from tools : "tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:19:08 [INF] <13> Executing MediaInfo : "--Output=XML \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
16:19:11 [INF] <13> Executing MkvMerge : "--identify \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\" --identification-format json"
16:19:11 [INF] <13> Executing FfProbe : "-loglevel quiet -show_streams -show_format -print_format json \"/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv\""
16:19:11 [INF] <13> "MediaInfo" : Type: "VideoInfo", Format: "AVC", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "eng", Id: 1, Number: 0, Title: "", Default: True, Profile: "High@4", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "MediaInfo" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 2, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "MediaInfo" : Type: "SubtitleInfo", Format: "UTF-8", Codec: "S_TEXT/UTF8", Language: "eng", Id: 3, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "MkvMerge" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "eng", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "MkvMerge" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "MkvMerge" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "FfProbe" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "eng", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "FfProbe" : Type: "AudioInfo", Format: "eac3", Codec: "ATSC A/52B (AC-3, E-AC-3)", Language: "eng", Id: 1, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> "FfProbe" : Type: "SubtitleInfo", Format: "subrip", Codec: "SubRip subtitle", Language: "eng", Id: 2, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
16:19:11 [INF] <13> Sidecar updated : State: SetLanguage, Verified, ClearedTags : "tv.show.s11e23.1080p.web.h264-cakes.PlexCleaner"
16:19:11 [INF] <13> "Process" (100.00%) After : "/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:19:11 [INF] <1> Completed "Process"
16:19:11 [INF] <1> Processing time : 00:24:28.2273725
16:19:11 [INF] <1> Total files : 1
16:19:11 [INF] <1> Error files : 0
16:19:11 [INF] <1> Modified files : 1
16:19:11 [INF] <1> Modified: SetLanguage, Verified, ClearedTags : "/clean/tv.show.s11e23.1080p.web.h264-cakes.mkv"
16:19:11 [INF] <1> VerifyFailed files : 0
16:19:11 [INF] <1> Deleting empty folders ...
16:19:11 [INF] <13> Looking for empty folders in "/clean"
16:19:11 [INF] <1> Deleted folders : 1

--------------
Clean succeeded (0h:24m:31s)

and here is my plexcleaner.json file:

{
  "$schema": "https://raw.githubusercontent.com/ptr727/PlexCleaner/develop/PlexCleaner.schema.json",
  "SchemaVersion": 2,
  "ToolsOptions": {
    "UseSystem": true,
    "RootPath": "",
    "RootRelative": false,
    "AutoUpdate": false
  },
  "ConvertOptions": {
    "EnableH265Encoder": true,
    "VideoEncodeQuality": 20,
    "AudioEncodeCodec": "ac3"
  },
  "ProcessOptions": {
    "DeleteEmptyFolders": true,
    "DeleteUnwantedExtensions": true,
    "KeepExtensions": [
      ".partial~",
      ".nfo",
      ".jpg",
      ".srt",
      ".smi",
      ".ssa",
      ".ass",
      ".vtt"
    ],
    "ReMux": true,
    "ReMuxExtensions": [
      ".avi",
      ".m2ts",
      ".ts",
      ".vob",
      ".mp4",
      ".m4v",
      ".asf",
      ".wmv"
    ],
    "DeInterlace": true,
    "ReEncode": true,
    "ReEncodeVideo": [
      {
        "Format": "mpeg2video"
      },
      {
        "Format": "vc1"
      },
      {
        "Format": "wmv3"
      },
      {
        "Format": "msrle"
      },
      {
        "Format": "rawvideo"
      },
      {
        "Format": "indeo5"
      },
      {
        "Format": "h264",
        "Profile": "Constrained Baseline@30"
      },
      {
        "Format": "mpeg4",
        "Codec": "dx50"
      },
      {
        "Format": "msmpeg4v2",
        "Codec": "mp42"
      },
      {
        "Format": "msmpeg4v3",
        "Codec": "div3"
      }
    ],
    "ReEncodeAudioFormats": [
      "flac",
      "mp2",
      "vorbis",
      "wmapro",
      "opus",
      "wmav2",
      "adpcm_ms",
      "pcm_u8",
      "pcm_s16le"
    ],
    "SetUnknownLanguage": true,
    "DefaultLanguage": "eng",
    "RemoveUnwantedLanguageTracks": true,
    "KeepLanguages": [
      "eng"
    ],
    "RemoveDuplicateTracks": true,
    "PreferredAudioFormats": [
      "truehd atmos",
      "truehd",
      "dts-hd master audio",
      "dts-hd high resolution audio",
      "dts",
      "e-ac-3",
      "ac-3"
    ],
    "RemoveTags": true,
    "UseSidecarFiles": true,
    "SidecarUpdateOnToolChange": false,
    "Verify": true,
    "RestoreFileTimestamp": false,
    "FileIgnoreList": []
  },
  "MonitorOptions": {
    "MonitorWaitTime": 60,
    "FileRetryWaitTime": 5,
    "FileRetryCount": 2
  },
  "VerifyOptions": {
    "AutoRepair": true,
    "DeleteInvalidFiles": false,
    "RegisterInvalidFiles": false,
    "MinimumDuration": 300,
    "VerifyDuration": 0,
    "IdetDuration": 0,
    "MaximumBitrate": 100000000,
    "MinimumFileAge": 0
  }
}

The resulting file is still 4.4GB. Did it even do anything?
Do I need to adjust the config in some way? I expect the x264->x265 to give me at least "some" compression...
If it's not doing the conversion.. how can I force this? I want anything non x264 to be x265, my main goal here is optimal disk usage.

Thanks!

Some way to run in parallel?

I've noticed that the ffmpeg options won't utilize all cores -- is there a setting that allows configuring a target number of cores and/or running multiple threads when processing a large number of files? I'm on a 5950x so I'd like to max it out as it process 7k files rather than wait 3x as long.

Would it work if I run several instances of PlexCleaner at the same time, or would that cause synchronization issues as the instances try to tackle the same files at the same time?

Release develop builds as pre-release

Using GitVersion mainline mode fails when master contains pre-release tags.
Figure out how to use mainline mode and release master and develop to releases.
Possibly using the isPreRelease option.

HEVC can't direct play in most environments, might be good to add to default ReEncodeVideo list

I was processing a large list of files and I noticed some were HEVC and didn't get automatically converted. HEVC as far as I can tell doesn't work in direct play in any players I've tried, so I added it to my list as follows:

    "ReEncodeVideo": [
    ...
      {
        "Format": "hevc"
      },
     ...

and now I have no issues. Just thought I'd report this as it might be a good idea to add it to the defaults

NullReferenceException

I have been getting this error consistently. It does not seem to be tied to a particular file, but happens when I am about 15% through running process on a large folder of nested movies and tv shows.

  • Windows 10
  • PlexCleaner 2.8.13
  • not running in parallel mode (also happens in parallel mode though)

error:

10:52:22 [ERR] <1> "ProcessFilesDriver"
System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.)
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at PlexCleaner.SidecarFile.ReadJson() in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/SidecarFile.cs:line 487
   at PlexCleaner.SidecarFile.Read(Boolean& current, Boolean verify) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/SidecarFile.cs:line 128
   at PlexCleaner.SidecarFile.Open(Boolean modified) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/SidecarFile.cs:line 232
   at PlexCleaner.ProcessFile.Refresh(Boolean modified) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/ProcessFile.cs:line 1399
   at PlexCleaner.Process.ProcessFile(String fileName, Boolean& modified, States& state, String& processName) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 470
   at PlexCleaner.Process.<>c__DisplayClass5_0.<ProcessFiles>b__0(String fileName) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 220
   at PlexCleaner.Process.<>c__DisplayClass16_0.<ProcessFilesDriver>b__1(IGrouping`2 keyPair) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 727
   at System.Linq.Parallel.ForAllOperator`1.ForAllEnumerator`1.MoveNext(TInput& currentElement, Int32& currentKey)
   at System.Linq.Parallel.ForAllSpoolingTask`2.SpoolingWork()
   at System.Linq.Parallel.SpoolingTaskBase.Work()
   at System.Linq.Parallel.QueryTask.BaseWork(Object unused)
   at System.Linq.Parallel.QueryTask.RunTaskSynchronously(Object o)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
   --- End of inner exception stack trace ---
   at System.Linq.Parallel.QueryTaskGroupState.QueryEnd(Boolean userInitiatedDispose)
   at System.Linq.Parallel.SpoolingTask.SpoolForAll[TInputOutput,TIgnoreKey](QueryTaskGroupState groupState, PartitionedStream`2 partitions, TaskScheduler taskScheduler)
   at System.Linq.Parallel.DefaultMergeHelper`2.System.Linq.Parallel.IMergeHelper<TInputOutput>.Execute()
   at System.Linq.Parallel.MergeExecutor`1.Execute()
   at System.Linq.Parallel.MergeExecutor`1.Execute[TKey](PartitionedStream`2 partitions, Boolean ignoreOutput, ParallelMergeOptions options, TaskScheduler taskScheduler, Boolean isOrdered, CancellationState cancellationState, Int32 queryId)
   at System.Linq.Parallel.PartitionedStreamMerger`1.Receive[TKey](PartitionedStream`2 partitionedStream)
   at System.Linq.Parallel.ForAllOperator`1.WrapPartitionedStream[TKey](PartitionedStream`2 inputStream, IPartitionedStreamRecipient`1 recipient, Boolean preferStriping, QuerySettings settings)
   at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.ChildResultsRecipient.Receive[TKey](PartitionedStream`2 inputStream)
   at System.Linq.Parallel.PartitionerQueryOperator`1.PartitionerQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
   at System.Linq.Parallel.UnaryQueryOperator`2.UnaryQueryOperatorResults.GivePartitionedStream(IPartitionedStreamRecipient`1 recipient)
   at System.Linq.Parallel.QueryOperator`1.GetOpenedEnumerator(Nullable`1 mergeOptions, Boolean suppressOrder, Boolean forEffect, QuerySettings querySettings)
   at System.Linq.Parallel.ForAllOperator`1.RunSynchronously()
   at System.Linq.ParallelEnumerable.ForAll[TSource](ParallelQuery`1 source, Action`1 action)
   at PlexCleaner.Process.ProcessFilesDriver(List`1 fileList, String taskName, Func`2 taskFunc) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 714
10:52:22 [INF] <1> Completed "Process"
10:52:22 [INF] <1> Processing time : 00:00:01.9141056
10:52:22 [INF] <1> Total files : 11513
10:52:22 [INF] <1> Error files : 0
10:52:22 [INF] <1> Modified files : 0
10:52:22 [INF] <1> VerifyFailed files : 0
10:52:22 [INF] <1> Deleting empty folders ...
10:52:22 [INF] <1> Looking for empty folders in "D:\\Plex"
10:52:22 [INF] <1> Deleted folders : 0

MediaInfo segmentation fault on Alpine

$ mediainfo --version
MediaInfo Command line,
MediaInfoLib - v23.03
~ $ mediainfo --Output=XML "/media/VC1 - foo.mkv"
Segmentation fault

Waiting for next MediaInfo version to address the issue.

Question: DefaultSettings Re-encode

Apologies, I couldn't find a way to just ask you a question.

I primarily use a Roku and saw your note "Some H.264 video profiles like "Constrained Baseline@30" cause hangs on Roku, re-encode to H.264 "High@40"."

The default settings show:
"Format": "h264",
"Profile": "Constrained Baseline@30"

So does that mean it is encoding FROM Constrained Baseline@30 or should I change that in the file to High@40 since I'm 99% Roku based?

Some sort of bitrate related bug

I have some mkv files that throw this error when I try to run them through plex cleaner:

 ---> (Inner Exception #4) System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at PlexCleaner.BitrateInfo.Calculate(List`1 packetList, Int32 videoStream, Int32 audioStream, Int32 threshold) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/BitrateInfo.cs:line 0
   at PlexCleaner.ProcessFile.GetBitrateInfo(BitrateInfo& bitrateInfo) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/ProcessFile.cs:line 1497
   at PlexCleaner.ProcessFile.VerifyBitrate() in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/ProcessFile.cs:line 1067
   at PlexCleaner.ProcessFile.Verify(Boolean& modified) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/ProcessFile.cs:line 957
   at PlexCleaner.Process.ProcessFile(String fileName, Boolean& modified, States& state, String& processName) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 430
   at PlexCleaner.Process.<>c__DisplayClass5_0.<ProcessFiles>b__0(String fileName) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 177
   at PlexCleaner.Process.<>c__DisplayClass16_0.<ProcessFilesDriver>b__1(IGrouping`2 keyPair) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Process.cs:line 736
   at System.Linq.Parallel.ForAllOperator`1.ForAllEnumerator`1.MoveNext(TInput& currentElement, Int32& currentKey)
   at System.Linq.Parallel.ForAllSpoolingTask`2.SpoolingWork()
   at System.Linq.Parallel.SpoolingTaskBase.Work()
   at System.Linq.Parallel.QueryTask.BaseWork(Object unused)
   at System.Linq.Parallel.QueryTask.<>c.<.cctor>b__10_0(Object o)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)<---

My workaround right now is to handbrake them manually first, but I'm guessing this might be a simple index out of bounds fix

FFmpeg v5 PPA fails to install on Ubuntu Focal

FFmpeg 5 PPA no longer installs on Ubuntu.

Error in GitHub Actions pipeline:
https://github.com/ptr727/PlexCleaner/runs/5531596900?check_suite_focus=true

Error in docker build:

#8 62.22 Some packages could not be installed. This may mean that you have
#8 62.22 requested an impossible situation or if you are using the unstable
#8 62.22 distribution that some required packages have not yet been created
#8 62.22 or been moved out of Incoming.
#8 62.22 The following information may help to resolve the situation:
#8 62.22
#8 62.22 The following packages have unmet dependencies:
#8 62.30 ffmpeg : Depends: libavcodec59 (= 7:5.0-2ubuntu0~20.04.sav1)
#8 62.30 Depends: libavdevice59 (= 7:5.0-2ubuntu0~20.04.sav1) but it is not going to be installed
#8 62.30 Depends: libavfilter8 (= 7:5.0-2ubuntu0~20.04.sav1)
#8 62.30 Depends: libavformat59 (= 7:5.0-2ubuntu0~20.04.sav1)
#8 62.31 E: Unable to correct problems, you have held broken packages.

PPA bug report:
https://bugs.launchpad.net/savos/+bug/1965181

unable get ffmpeg

Is this a new issue that can be reproduced?

  • This is a new issue that can be reproduced.

Which operating systems reproduce the issue?

  • Windows
  • Docker
  • Other

Version information.

OS Version: E.g. Windows 10 Pro 22H2.

Steps to reproduce?

I just ran the command line

Commandline.

PlexCleaner checkfornewtools --settingsfile PlexCleaner.json

Relevant log output.

PlexCleaner checkfornewtools --settingsfile PlexCleaner.json
14:10:05 [INF] <1> Loading settings from : "PlexCleaner.json"
14:10:05 [INF] <1> Application Version : "3.1.24+d77820f206.d77820f2063b22373fb736670320c391a4488e7d", Runtime Version : "7.0.5", Debug Build: False
14:10:05 [INF] <1> Parallel Processing: False : Thread Count: 1, Processor Count: 16
14:10:05 [INF] <1> Checking for new tools ...
14:10:05 [INF] <1> Getting latest version of FfMpeg ...
14:10:36 [ERR] <1> "GetContentInfo"
System.AggregateException: One or more errors occurred. (A task was canceled.)
 ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Threading.Tasks.Task.GetExceptions(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at InsaneGenius.Utilities.Download.GetContentInfo(Uri uri, Int64& size, DateTime& modifiedTime)
   at PlexCleaner.Tools.GetUrlDetails(MediaToolInfo mediaToolInfo) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Tools.cs:line 339
   at PlexCleaner.Tools.CheckForNewTools() in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Tools.cs:line 265
   at PlexCleaner.Program.CheckForNewToolsCommand(CommandLineOptions options) in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Program.cs:line 160
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.InvokeAsync(InvocationContext context)
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.InvokeAsync(InvocationContext context)
   at System.CommandLine.NamingConventionBinder.ModelBindingCommandHandler.Invoke(InvocationContext context)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<BuildInvocationChain>b__0(InvocationContext invocationContext, Func`2 _)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass17_0.<<UseParseErrorReporting>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass17_0.<UseParseErrorReporting>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass12_0.<<UseHelp>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass12_0.<UseHelp>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseVersionOption>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<UseVersionOption>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass19_0.<<UseTypoCorrections>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass19_0.<UseTypoCorrections>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__18_0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<UseSuggestDirective>b__18_0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass16_0.<<UseParseDirective>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass16_0.<UseParseDirective>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__5_0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<RegisterWithDotnetSuggest>b__5_0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<UseEnvironmentVariableDirective>b__6_0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass8_0.<<UseExceptionHandler>b__0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass8_0.<UseExceptionHandler>b__0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_2.<BuildInvocationChain>b__3(InvocationContext c)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<CancelOnProcessTermination>b__1_0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<CancelOnProcessTermination>b__1_0(InvocationContext context, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_1.<BuildInvocationChain>b__2(InvocationContext ctx, Func`2 next)
   at System.CommandLine.Invocation.InvocationPipeline.<Invoke>g__FullInvocationChain|3_0(InvocationContext context)
   at System.CommandLine.Invocation.InvocationPipeline.Invoke(IConsole console)
   at System.CommandLine.CommandExtensions.Invoke(Command command, String[] args, IConsole console)
   at PlexCleaner.CommandLineOptions.Invoke() in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/CommandLineOptions.cs:line 30
   at PlexCleaner.Program.Main() in /home/runner/work/PlexCleaner/PlexCleaner/PlexCleaner/Program.cs:line 44
--- End of stack trace from previous location ---

   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at InsaneGenius.Utilities.Download.GetContentInfo(Uri uri, Int64& size, DateTime& modifiedTime)
14:10:36 [ERR] <1> FfMpeg : Failed to get latest version
14:10:36 [INF] <1> Exit Code : 1

Settings file.

{
"$schema": "https://raw.githubusercontent.com/ptr727/PlexCleaner/main/PlexCleaner.schema.json",
"SchemaVersion": 3,
"ToolsOptions": {
"UseSystem": false,
"RootPath": ".\Tools\",
"RootRelative": true,
"AutoUpdate": true
},
"ProcessOptions": {
"KeepOriginalLanguage": true,
"RemoveClosedCaptions": true,
"SetIetfLanguageTags": true,
"SetTrackFlags": true,
"KeepExtensions": [
".partial~",
".nfo",
".jpg",
".srt",
".smi",
".ssa",
".ass",
".vtt"
],
"ReMuxExtensions": [
".avi",
".m2ts",
".ts",
".vob",
".mp4",
".m4v",
".asf",
".wmv"
],
"ReEncodeVideo": [
{
"Format": "mpeg2video"
},
{
"Format": "vc1"
},
{
"Format": "wmv3"
},
{
"Format": "msrle"
},
{
"Format": "rawvideo"
},
{
"Format": "indeo5"
},
{
"Format": "h264",
"Profile": "Constrained Baseline@30"
},
{
"Format": "mpeg4",
"Codec": "dx50"
},
{
"Format": "msmpeg4v2",
"Codec": "mp42"
},
{
"Format": "msmpeg4v3",
"Codec": "div3"
}
],
"ReEncodeAudioFormats": [
"flac",
"mp2",
"vorbis",
"wmapro",
"opus",
"wmav2",
"adpcm_ms",
"pcm_u8",
"pcm_s16le"
],
"KeepLanguages": [
"en",
"af",
"zh",
"in"
],
"PreferredAudioFormats": [
"truehd atmos",
"truehd",
"dts-hd master audio",
"dts-hd high resolution audio",
"dts",
"e-ac-3",
"ac-3"
],
"DeleteEmptyFolders": true,
"DeleteUnwantedExtensions": true,
"ReMux": true,
"DeInterlace": true,
"ReEncode": true,
"SetUnknownLanguage": true,
"DefaultLanguage": "en",
"RemoveUnwantedLanguageTracks": false,
"RemoveDuplicateTracks": false,
"RemoveTags": true,
"UseSidecarFiles": true,
"SidecarUpdateOnToolChange": false,
"Verify": true,
"RestoreFileTimestamp": false,
"FileIgnoreList": []
},
"ConvertOptions": {
"FfMpegOptions": {
"Video": "libx264 -crf 22 -preset medium",
"Audio": "ac3",
"Global": "-analyzeduration 2147483647 -probesize 2147483647",
"Output": "-max_muxing_queue_size 1024 -abort_on empty_output"
},
"HandBrakeOptions": {
"Video": "x264 --quality 22 --encoder-preset medium",
"Audio": "copy --audio-fallback ac3"
}
},
"VerifyOptions": {
"AutoRepair": true,
"DeleteInvalidFiles": false,
"RegisterInvalidFiles": false,
"MaximumBitrate": 100000000
},
"MonitorOptions": {
"MonitorWaitTime": 60,
"FileRetryWaitTime": 5,
"FileRetryCount": 2
}
}

Log file.

No response

Media file information.

No response

HandBrakeCLI hangs or runs extremely slowly in parallel mode

When running in parallel mode HandBrakeCLI appears to hang after 20+ hours.

Have been unable to replicate in non-parallel mode, and have thus far failed to attach the debugger to investigate stdout or stderr process capture.

2023-02-12 05:56:52.232 +00:00 [INF] <18> "Process" (77.35%) Before : "/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:56:52.233 +00:00 [INF] <18> Reading media info from tools : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:56:52.233 +00:00 [INF] <18> Executing MediaInfo : "--Output=XML \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\""
2023-02-12 05:56:52.599 +00:00 [INF] <18> Executing MkvMerge : "--identify \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\" --identification-format json"
2023-02-12 05:56:52.737 +00:00 [INF] <18> Executing FfProbe : "-loglevel quiet -show_streams -show_format -print_format json \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\""
2023-02-12 05:56:52.929 +00:00 [INF] <18> "MediaInfo" : Type: "VideoInfo", Format: "AVC", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 1, Number: 0, Title: "", Default: True, Profile: "High@4", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.929 +00:00 [INF] <18> "MediaInfo" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 2, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.929 +00:00 [INF] <18> "MediaInfo" : Type: "SubtitleInfo", Format: "UTF-8", Codec: "S_TEXT/UTF8", Language: "eng", Id: 3, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.929 +00:00 [INF] <18> "MkvMerge" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.930 +00:00 [INF] <18> "MkvMerge" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.930 +00:00 [INF] <18> "MkvMerge" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.930 +00:00 [INF] <18> "FfProbe" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "und", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.930 +00:00 [INF] <18> "FfProbe" : Type: "AudioInfo", Format: "eac3", Codec: "ATSC A/52B (AC-3, E-AC-3)", Language: "eng", Id: 1, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.930 +00:00 [INF] <18> "FfProbe" : Type: "SubtitleInfo", Format: "subrip", Codec: "SubRip subtitle", Language: "eng", Id: 2, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:52.941 +00:00 [INF] <18> Sidecar created : State: None : "Grand Designs New Zealand - S07E04 - Round House.PlexCleaner"
2023-02-12 05:56:52.941 +00:00 [INF] <18> Finding Closed Captions in video stream : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:56:52.941 +00:00 [INF] <18> Executing FfProbe : "-hide_banner \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\""
2023-02-12 05:56:53.166 +00:00 [INF] <18> Removing Closed Captions from video stream : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:56:53.166 +00:00 [INF] <18> "Closed Captions" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "und", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:56:53.166 +00:00 [INF] <18> Removing Closed Captions using FfMpeg : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:56:53.166 +00:00 [INF] <18> Executing FfMpeg : "-analyzeduration 2147483647 -probesize 2147483647 -i \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\" -max_muxing_queue_size 1024 -abort_on empty_output -hide_banner -nostats -map 0 -c copy -bsf:v \"filter_units=remove_types=6\" -f matroska \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.tmp\""
2023-02-12 05:57:15.782 +00:00 [INF] <18> Waiting for IO to flush : 5s : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:57:20.783 +00:00 [INF] <18> Reading media info from tools : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:57:20.787 +00:00 [INF] <18> Executing MediaInfo : "--Output=XML \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\""
2023-02-12 05:57:20.968 +00:00 [INF] <18> Executing MkvMerge : "--identify \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\" --identification-format json"
2023-02-12 05:57:21.153 +00:00 [INF] <18> Executing FfProbe : "-loglevel quiet -show_streams -show_format -print_format json \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\""
2023-02-12 05:57:21.426 +00:00 [INF] <18> "MediaInfo" : Type: "VideoInfo", Format: "AVC", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 1, Number: 0, Title: "", Default: True, Profile: "High@4", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.427 +00:00 [INF] <18> "MediaInfo" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 2, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.429 +00:00 [INF] <18> "MediaInfo" : Type: "SubtitleInfo", Format: "UTF-8", Codec: "S_TEXT/UTF8", Language: "eng", Id: 3, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.429 +00:00 [INF] <18> "MkvMerge" : Type: "VideoInfo", Format: "AVC/H.264/MPEG-4p10", HDR: "", Codec: "V_MPEG4/ISO/AVC", Language: "und", Id: 0, Number: 1, Title: "", Default: True, Profile: "", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.432 +00:00 [INF] <18> "MkvMerge" : Type: "AudioInfo", Format: "E-AC-3", Codec: "A_EAC3", Language: "eng", Id: 1, Number: 2, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.432 +00:00 [INF] <18> "MkvMerge" : Type: "SubtitleInfo", Format: "SubRip/SRT", Codec: "S_TEXT/UTF8", Language: "eng", Id: 2, Number: 3, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.432 +00:00 [INF] <18> "FfProbe" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "und", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: False, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.433 +00:00 [INF] <18> "FfProbe" : Type: "AudioInfo", Format: "eac3", Codec: "ATSC A/52B (AC-3, E-AC-3)", Language: "eng", Id: 1, Number: 1, Title: "", Default: True, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.433 +00:00 [INF] <18> "FfProbe" : Type: "SubtitleInfo", Format: "subrip", Codec: "SubRip subtitle", Language: "eng", Id: 2, Number: 2, Title: "", Default: False, Forced: False, State: None, HasErrors: False, HasTags: False
2023-02-12 05:57:21.454 +00:00 [INF] <18> Sidecar updated : State: ClearedCaptions : "Grand Designs New Zealand - S07E04 - Round House.PlexCleaner"
2023-02-12 05:57:21.466 +00:00 [INF] <18> Counting interlaced frames : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 05:57:21.467 +00:00 [INF] <18> Executing FfMpeg : "-analyzeduration 2147483647 -probesize 2147483647 -i \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\" -max_muxing_queue_size 1024 -abort_on empty_output -hide_banner -nostats -hide_banner -nostats -xerror -filter:v idet -an -f rawvideo -y /dev/null"
2023-02-12 06:11:20.438 +00:00 [INF] <18> FfMpeg Idet: Interlaced: True (11.74 % > 5.00 %), Interlaced: 17427, Progressive: 131022, Undetermined: 11217, Total: 159666 : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 06:11:20.439 +00:00 [WRN] <18> Idet reported interlaced, metadata reported not interlaced : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 06:11:20.439 +00:00 [INF] <18> Deinterlacing interlaced video : "Grand Designs New Zealand - S07E04 - Round House.mkv"
2023-02-12 06:11:20.439 +00:00 [INF] <18> "Interlaced" : Type: "VideoInfo", Format: "h264", HDR: "", Codec: "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", Language: "und", Id: 0, Number: 0, Title: "", Default: True, Profile: "High@40", Interlaced: True, ClosedCaptions: False, State: None, HasErrors: False, HasTags: False
2023-02-12 06:11:20.439 +00:00 [INF] <18> Executing HandBrake : "--input \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.mkv\" --output \"/media/Series/Grand Designs New Zealand/Season 7/Grand Designs New Zealand - S07E04 - Round House.tmp1\" --format av_mkv --encoder x265 --encoder-preset medium --quality 20 --comb-detect --decomb --subtitle none --all-audio --aencoder copy --audio-fallback ac3"

image

Refresh sidecar files when tool version changes

Sidecar file contents can be out of date if teh creating tool version changed.
Find a way to dynamically re-create sidecar files when the tool version has changed.
E.g. write tool version in sidecar header.
E.g. compare sidecar modified date with last tool update date.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.